/*
 * epsonds.c - Epson ESC/I-2 driver.
 *
 * Copyright (C) 2015 Tower Technologies
 * Author: Alessandro Zummo <a.zummo@towertech.it>
 *
 * This file is part of the SANE package.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, version 2.
 */

#define EPSONDS_VERSION		1
#define EPSONDS_REVISION	1
#define EPSONDS_BUILD		0

/* debugging levels:
 *
 *	32	eds_send
 *	30	eds_recv
 *	20	sane_read and related
 *	18	sane_read and related
 *	17	setvalue, getvalue, control_option
 *	16
 *	15	esci2_img
 *	13	image_cb
 *	12	eds_control
 *	11	all received params
 *	10	some received params
 *	 9
 *	 8	esci2_xxx
 *	 7	open/close/attach
 *	 6	print_params
 *	 5	basic functions
 *	 3	JPEG decompressor
 *	 1	scanner info and capabilities
 *	 0	errors
 */

#include "sane/config.h"

#include <ctype.h>
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <math.h>

#include "sane/saneopts.h"
#include "sane/sanei_config.h"
#include "sane/sanei_tcp.h"
#include "sane/sanei_udp.h"

#include "epsonds.h"
#include "epsonds-usb.h"
#include "epsonds-io.h"
#include "epsonds-cmd.h"
#include "epsonds-ops.h"
#include "epsonds-jpeg.h"
#include "epsonds-net.h"

static SANE_Status
setvalue(SANE_Handle handle, SANE_Int option, void *value, SANE_Int *info);
/*
 * Definition of the mode_param struct, that is used to
 * specify the valid parameters for the different scan modes.
 *
 * The depth variable gets updated when the bit depth is modified.
 */


static unsigned char LUT[][256] =
{
    {// 0
        0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
        0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
        0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
        0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
        0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
        0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
        0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
        0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
        0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
        0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
        0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,
        0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
        0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
        0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
        0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
        0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
        0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
        0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
        0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,
        0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
        0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,
        0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
        0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,
        0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
        0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,
        0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
        0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,
        0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
        0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,
        0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
        0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,
        0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
    },
    {	//  1
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
        0x02,0x03,0x04,0x06,0x07,0x09,0x0B,0x0D,
        0x10,0x12,0x14,0x17,0x19,0x1B,0x1E,0x20,
        0x22,0x24,0x26,0x28,0x2A,0x2C,0x2E,0x30,
        0x32,0x33,0x35,0x37,0x39,0x3B,0x3C,0x3E,
        0x40,0x41,0x43,0x45,0x46,0x48,0x4A,0x4B,
        0x4D,0x4F,0x50,0x52,0x53,0x55,0x57,0x58,
        0x5A,0x5B,0x5D,0x5E,0x60,0x61,0x63,0x64,
        0x66,0x67,0x69,0x6A,0x6C,0x6D,0x6F,0x70,
        0x71,0x73,0x74,0x76,0x77,0x79,0x7A,0x7B,
        0x7D,0x7E,0x7F,0x81,0x82,0x84,0x85,0x86,
        0x88,0x89,0x8A,0x8C,0x8D,0x8E,0x90,0x91,
        0x92,0x94,0x95,0x96,0x98,0x99,0x9A,0x9C,
        0x9D,0x9E,0xA0,0xA1,0xA2,0xA3,0xA5,0xA6,
        0xA7,0xA8,0xAA,0xAB,0xAC,0xAE,0xAF,0xB0,
        0xB1,0xB3,0xB4,0xB5,0xB6,0xB8,0xB9,0xBA,
        0xBB,0xBC,0xBE,0xBF,0xC0,0xC1,0xC3,0xC4,
        0xC5,0xC6,0xC7,0xC9,0xCA,0xCB,0xCC,0xCD,
        0xCF,0xD0,0xD1,0xD2,0xD3,0xD5,0xD6,0xD7,
        0xD8,0xD9,0xDA,0xDC,0xDD,0xDE,0xDF,0xE0,
        0xE1,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,
        0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF3,
        0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFB,0xFC,
        0xFD,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
    },
    {	// 2
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
		0x02,0x03,0x04,0x05,0x07,0x08,0x0A,0x0C,
		0x0E,0x10,0x12,0x14,0x16,0x16,0x19,0x1B,
		0x1D,0x1F,0x21,0x23,0x25,0x27,0x28,0x2A,
		0x2C,0x2E,0x30,0x32,0x33,0x35,0x37,0x39,
		0x3A,0x3C,0x3E,0x40,0x41,0x43,0x45,0x46,
		0x48,0x4A,0x4B,0x4D,0x4F,0x50,0x52,0x53,
		0x55,0x57,0x58,0x5A,0x5B,0x5D,0x5F,0x60,
		0x62,0x63,0x65,0x66,0x68,0x69,0x6B,0x6C,
		0x6E,0x6F,0x71,0x72,0x74,0x75,0x77,0x78,
		0x7A,0x7B,0x7D,0x7E,0x80,0x81,0x83,0x84,
		0x86,0x87,0x88,0x8A,0x8B,0x8D,0x8E,0x90,
		0x91,0x92,0x94,0x95,0x97,0x98,0x99,0x9B,
		0x9C,0x9E,0x9F,0xA0,0xA2,0xA3,0xA5,0xA7,
		0xA9,0xAA,0xAB,0xAD,0xAE,0xB0,0xB1,0xB2,
		0xB4,0xB5,0xB6,0xB8,0xB9,0xBA,0xBC,0xBD,
		0xBE,0xC0,0xC1,0xC2,0xC4,0xC5,0xC6,0xC8,
		0xC9,0xCA,0xCC,0xCD,0xCE,0xD0,0xD1,0xD2,
		0xD4,0xD5,0xD6,0xD7,0xD9,0xDA,0xDB,0xDD,
		0xDE,0xDF,0xE1,0xE2,0xE3,0xE4,0xE6,0xE7,
		0xE8,0xE9,0xEB,0xEC,0xED,0xEF,0xF0,0xF1,
		0xF2,0xF4,0xF5,0xF6,0xF7,0xF9,0xFA,0xFB,
		0xFC,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
    },
    {	// 3
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x07,
		0x08,0x0A,0x0C,0x0E,0x10,0x12,0x14,0x16,
		0x18,0x1A,0x1C,0x1E,0x20,0x22,0x24,0x26,
		0x28,0x2A,0x2B,0x2D,0x2F,0x31,0x33,0x34,
		0x36,0x38,0x39,0x3B,0x3D,0x3E,0x40,0x42,
		0x43,0x45,0x47,0x48,0x4A,0x4B,0x4D,0x4F,
		0x50,0x52,0x53,0x55,0x56,0x58,0x59,0x5B,
		0x5D,0x5E,0x60,0x61,0x63,0x64,0x66,0x67,
		0x69,0x6A,0x6B,0x6D,0x6E,0x70,0x71,0x73,
		0x74,0x76,0x77,0x79,0x7A,0x7B,0x7D,0x7E,
		0x80,0x81,0x83,0x84,0x85,0x87,0x88,0x8A,
		0x8B,0x8C,0x8E,0x8F,0x90,0x92,0x93,0x95,
		0x96,0x97,0x99,0x9A,0x9B,0x9D,0x9E,0x9F,
		0xA1,0xA2,0xA3,0xA5,0xA6,0xA7,0xA9,0xAA,
		0xAB,0xAD,0xAE,0xAF,0xB1,0xB2,0xB3,0xB5,
		0xB6,0xB7,0xB9,0xBA,0xBB,0xBD,0xBE,0xBF,
		0xC0,0xC2,0xC3,0xC4,0xC6,0xC7,0xC8,0xC9,
		0xCB,0xCC,0xCD,0xCF,0xD0,0xD1,0xD2,0xD4,
		0xD5,0xD6,0xD7,0xD9,0xDA,0xDB,0xDC,0xDF,
		0xE0,0xE1,0xE3,0xE4,0xE5,0xE6,0xE8,0xE9,
		0xEA,0xEB,0xED,0xEE,0xEF,0xF0,0xF2,0xF3,
		0xF4,0xF5,0xF6,0xF8,0xF9,0xFA,0xFB,0xFD,
		0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
	},
	{	//4
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,
		0x04,0x05,0x07,0x08,0x0A,0x0C,0x0E,0x10,
		0x12,0x14,0x16,0x18,0x1A,0x1C,0x1E,0x20,
		0x22,0x24,0x26,0x28,0x2A,0x2B,0x2D,0x2F,
		0x31,0x33,0x34,0x36,0x38,0x39,0x3B,0x3D,
		0x3E,0x40,0x42,0x43,0x45,0x47,0x48,0x4A,
		0x4B,0x4D,0x4F,0x50,0x52,0x53,0x55,0x56,
		0x58,0x59,0x5B,0x5D,0x5E,0x60,0x61,0x63,
		0x64,0x66,0x67,0x69,0x6A,0x6B,0x6D,0x6E,
		0x70,0x71,0x73,0x74,0x76,0x77,0x79,0x7A,
		0x7B,0x7D,0x7E,0x80,0x81,0x83,0x84,0x85,
		0x87,0x88,0x8A,0x8B,0x8C,0x8E,0x8F,0x90,
		0x92,0x93,0x95,0x96,0x97,0x99,0x9A,0x9B,
		0x9D,0x9E,0x9F,0xA1,0xA2,0xA3,0xA5,0xA6,
		0xA7,0xA9,0xAA,0xAB,0xAD,0xAE,0xAF,0xB1,
		0xB2,0xB3,0xB5,0xB6,0xB7,0xB9,0xBA,0xBB,
		0xBD,0xBE,0xBF,0xC0,0xC2,0xC3,0xC4,0xC6,
		0xC7,0xC8,0xC9,0xCB,0xCC,0xCD,0xCF,0xD0,
		0xD1,0xD2,0xD4,0xD5,0xD6,0xD7,0xD9,0xDA,
		0xDB,0xDC,0xDE,0xDF,0xE0,0xE1,0xE3,0xE5,
		0xE6,0xE8,0xE9,0xEA,0xEB,0xED,0xEE,0xEF,
		0xF0,0xF2,0xF3,0xF4,0xF5,0xF6,0xF8,0xF9,
		0xFA,0xFB,0xFD,0xFE,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
    },
    {   // 5
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x01,0x02,0x03,0x04,0x05,0x07,0x08,0x0A,
        0x0C,0x0E,0x10,0x12,0x14,0x16,0x18,0x1A,
        0x1C,0x1E,0x20,0x22,0x24,0x26,0x28,0x2A,
        0x2B,0x2D,0x2F,0x31,0x33,0x34,0x36,0x38,
        0x39,0x3B,0x3D,0x3E,0x40,0x42,0x43,0x45,
        0x47,0x48,0x4A,0x4B,0x4D,0x4F,0x50,0x52,
        0x53,0x55,0x56,0x58,0x59,0x5B,0x5D,0x5E,
        0x60,0x61,0x63,0x64,0x66,0x67,0x69,0x6A,
        0x6B,0x6D,0x6E,0x70,0x71,0x73,0x74,0x76,
        0x77,0x79,0x7A,0x7B,0x7D,0x7E,0x80,0x81,
        0x83,0x84,0x85,0x87,0x88,0x8A,0x8B,0x8C,
        0x8E,0x8F,0x90,0x92,0x93,0x95,0x96,0x97,
        0x99,0x9A,0x9B,0x9D,0x9E,0x9F,0xA1,0xA2,
        0xA3,0xA5,0xA6,0xA7,0xA9,0xAA,0xAB,0xAD,
        0xAE,0xAF,0xB1,0xB2,0xB3,0xB5,0xB6,0xB7,
        0xB9,0xBA,0xBB,0xBD,0xBE,0xBF,0xC0,0xC2,
        0xC3,0xC4,0xC6,0xC7,0xC8,0xC9,0xCB,0xCC,
        0xCD,0xCF,0xD0,0xD1,0xD2,0xD4,0xD5,0xD6,
        0xD7,0xD9,0xDA,0xDB,0xDC,0xDE,0xDF,0xE0,
        0xE3,0xE4,0xE5,0xE6,0xE8,0xE9,0xEA,0xEB,
        0xED,0xEE,0xEF,0xF0,0xF2,0xF3,0xF4,0xF5,
        0xF6,0xF8,0xF9,0xFA,0xFB,0xFD,0xFE,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
    },
    {	// 6
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,
        0x03,0x04,0x05,0x07,0x08,0x0A,0x0C,0x0E,
        0x10,0x12,0x14,0x16,0x18,0x18,0x1A,0x1C,
        0x1E,0x20,0x22,0x24,0x26,0x27,0x29,0x2B,
        0x2C,0x2E,0x30,0x31,0x33,0x35,0x36,0x38,
        0x39,0x3B,0x3C,0x3E,0x40,0x41,0x43,0x44,
        0x45,0x47,0x48,0x4A,0x4B,0x4D,0x4E,0x50,
        0x51,0x52,0x54,0x55,0x56,0x58,0x59,0x5B,
        0x5C,0x5D,0x5F,0x60,0x61,0x63,0x64,0x65,
        0x67,0x68,0x69,0x6A,0x6C,0x6D,0x6E,0x70,
        0x71,0x72,0x73,0x75,0x76,0x77,0x78,0x7A,
        0x7B,0x7C,0x7D,0x7E,0x80,0x81,0x82,0x83,
        0x85,0x86,0x87,0x88,0x89,0x8A,0x8C,0x8D,
        0x8E,0x8F,0x90,0x92,0x93,0x94,0x95,0x96,
        0x97,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
        0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,
        0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,
        0xB2,0xB3,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,
        0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0xC2,0xC4,
        0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,
        0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD4,0xD5,
        0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,
        0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,
        0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,
        0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,
        0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,
        0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
    },
    {	// 7
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,
		0x03,0x04,0x05,0x06,0x07,0x09,0x0B,0x0C,
		0x0E,0x10,0x12,0x14,0x16,0x18,0x1A,0x1C,
		0x1E,0x20,0x21,0x23,0x25,0x27,0x28,0x2A,
		0x2C,0x2D,0x2F,0x31,0x32,0x34,0x36,0x37,
		0x39,0x3B,0x3C,0x3E,0x3F,0x41,0x42,0x44,
		0x45,0x47,0x48,0x4A,0x4B,0x4D,0x4E,0x50,
		0x51,0x53,0x54,0x56,0x57,0x59,0x5A,0x5C,
		0x5D,0x5F,0x60,0x61,0x63,0x64,0x66,0x67,
		0x68,0x6A,0x6B,0x6D,0x6E,0x6F,0x71,0x72,
		0x73,0x75,0x76,0x78,0x79,0x7A,0x7C,0x7D,
		0x7E,0x80,0x81,0x82,0x84,0x85,0x86,0x88,
		0x89,0x8A,0x8B,0x8D,0x8E,0x8F,0x91,0x92,
		0x93,0x95,0x96,0x97,0x98,0x9A,0x9B,0x9C,
		0x9E,0x9F,0xA0,0xA1,0xA3,0xA4,0xA5,0xA6,
		0xA8,0xA9,0xAA,0xAB,0xAD,0xAE,0xAF,0xB0,
		0xB2,0xB3,0xB4,0xB5,0xB7,0xB8,0xB9,0xBA,
		0xBC,0xBD,0xBE,0xBF,0xC0,0xC2,0xC3,0xC4,
		0xC5,0xC7,0xC8,0xC9,0xCA,0xCB,0xCD,0xCE,
		0xCF,0xD0,0xD1,0xD3,0xD4,0xD5,0xD6,0xD7,
		0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xE0,0xE1,
		0xE2,0xE3,0xE4,0xE6,0xE7,0xE8,0xE9,0xEA,
		0xEB,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,
		0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFC,0xFD,
		0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
    }
};

static unsigned char LUT_R[][256] =
{
    {	//  0
        0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
        0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
        0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
        0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
        0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
        0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
        0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
        0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
        0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
        0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
        0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,
        0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
        0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
        0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
        0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
        0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
        0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
        0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
        0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,
        0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
        0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,
        0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
        0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,
        0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
        0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,
        0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
        0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,
        0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
        0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,
        0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
        0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,
        0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
    },
    {	// 1
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
        0x02,0x03,0x04,0x06,0x07,0x09,0x0B,0x0D,
        0x10,0x12,0x14,0x17,0x19,0x1B,0x1E,0x20,
        0x22,0x24,0x26,0x28,0x2A,0x2C,0x2E,0x30,
        0x32,0x33,0x35,0x37,0x39,0x3B,0x3C,0x3E,
        0x40,0x41,0x43,0x45,0x46,0x48,0x4A,0x4B,
        0x4D,0x4F,0x50,0x52,0x53,0x55,0x57,0x58,
        0x5A,0x5B,0x5D,0x5E,0x60,0x61,0x63,0x64,
        0x66,0x67,0x69,0x6A,0x6C,0x6D,0x6F,0x70,
        0x71,0x73,0x74,0x76,0x77,0x79,0x7A,0x7B,
        0x7D,0x7E,0x7F,0x81,0x82,0x84,0x85,0x86,
        0x88,0x89,0x8A,0x8C,0x8D,0x8E,0x90,0x91,
        0x92,0x94,0x95,0x96,0x98,0x99,0x9A,0x9C,
        0x9D,0x9E,0xA0,0xA1,0xA2,0xA3,0xA5,0xA6,
        0xA7,0xA8,0xAA,0xAB,0xAC,0xAE,0xAF,0xB0,
        0xB1,0xB3,0xB4,0xB5,0xB6,0xB8,0xB9,0xBA,
        0xBB,0xBC,0xBE,0xBF,0xC0,0xC1,0xC3,0xC4,
        0xC5,0xC6,0xC7,0xC9,0xCA,0xCB,0xCC,0xCD,
        0xCF,0xD0,0xD1,0xD2,0xD3,0xD5,0xD6,0xD7,
        0xD8,0xD9,0xDA,0xDC,0xDD,0xDE,0xDF,0xE0,
        0xE1,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,
        0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF3,
        0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFB,0xFC,
        0xFD,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
    },
    {	// 2
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,
		0x03,0x04,0x05,0x07,0x08,0x0A,0x0C,0x0E,
		0x10,0x12,0x14,0x16,0x19,0x1B,0x1D,0x1F,
		0x21,0x23,0x25,0x27,0x28,0x2A,0x2C,0x2E,
		0x30,0x32,0x33,0x35,0x37,0x39,0x3A,0x3C,
		0x3E,0x40,0x41,0x43,0x45,0x46,0x48,0x4A,
		0x4B,0x4D,0x4F,0x50,0x52,0x53,0x55,0x57,
		0x58,0x5A,0x5B,0x5D,0x5F,0x60,0x62,0x63,
		0x65,0x66,0x68,0x69,0x6B,0x6C,0x6E,0x6F,
		0x71,0x72,0x74,0x75,0x77,0x78,0x7A,0x7B,
		0x7D,0x7E,0x80,0x81,0x83,0x84,0x86,0x87,
		0x88,0x8A,0x8B,0x8D,0x8E,0x90,0x91,0x92,
		0x94,0x95,0x97,0x98,0x99,0x9B,0x9C,0x9E,
		0x9F,0xA0,0xA2,0xA3,0xA5,0xA6,0xA7,0xA9,
		0xAA,0xAB,0xAD,0xAE,0xB0,0xB1,0xB2,0xB4,
		0xB5,0xB6,0xB8,0xB9,0xBA,0xBC,0xBD,0xBE,
		0xC0,0xC1,0xC2,0xC4,0xC5,0xC6,0xC8,0xC9,
		0xCA,0xCC,0xCD,0xCE,0xD0,0xD1,0xD2,0xD4,
		0xD5,0xD6,0xD7,0xD9,0xDA,0xDB,0xDD,0xDE,
		0xDF,0xE1,0xE2,0xE3,0xE4,0xE6,0xE7,0xE8,
		0xE9,0xEB,0xEC,0xED,0xEF,0xF0,0xF1,0xF2,
		0xF4,0xF5,0xF6,0xF7,0xF9,0xFA,0xFB,0xFC,
		0xFE,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
    },
    {
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x01,0x02,0x03,0x04,0x05,0x07,0x08,0x0A,
		0x0C,0x0E,0x10,0x12,0x14,0x16,0x18,0x1A,
		0x1C,0x1E,0x20,0x22,0x24,0x26,0x28,0x2A,
		0x2B,0x2D,0x2F,0x31,0x33,0x34,0x36,0x38,
		0x39,0x3B,0x3D,0x3E,0x40,0x42,0x43,0x45,
		0x47,0x48,0x4A,0x4B,0x4D,0x4F,0x50,0x52,
		0x53,0x55,0x56,0x58,0x59,0x5B,0x5D,0x5E,
		0x60,0x61,0x63,0x64,0x66,0x67,0x69,0x6A,
		0x6B,0x6D,0x6E,0x70,0x71,0x73,0x74,0x76,
		0x77,0x79,0x7A,0x7B,0x7D,0x7E,0x80,0x81,
		0x83,0x84,0x85,0x87,0x88,0x8A,0x8B,0x8C,
		0x8E,0x8F,0x90,0x92,0x93,0x95,0x96,0x97,
		0x99,0x9A,0x9B,0x9D,0x9E,0x9F,0xA1,0xA2,
		0xA3,0xA5,0xA6,0xA7,0xA9,0xAA,0xAB,0xAD,
		0xAE,0xAF,0xB1,0xB2,0xB3,0xB5,0xB6,0xB7,
		0xB9,0xBA,0xBB,0xBD,0xBE,0xBF,0xC0,0xC2,
		0xC3,0xC4,0xC6,0xC7,0xC8,0xC9,0xCB,0xCC,
		0xCD,0xCF,0xD0,0xD1,0xD2,0xD4,0xD5,0xD6,
		0xD7,0xD9,0xDA,0xDB,0xDC,0xDE,0xDF,0xE0,
		0xE1,0xE3,0xE4,0xE5,0xE5,0xE6,0xE8,0xE9,
		0xEA,0xEB,0xED,0xEE,0xEF,0xF0,0xF2,0xF3,
		0xF4,0xF5,0xF6,0xF8,0xF9,0xFA,0xFB,0xFD,
		0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
	},
	{
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,
		0x07,0x08,0x0A,0x0C,0x0E,0x10,0x12,0x14,
		0x16,0x18,0x1A,0x1C,0x1E,0x20,0x22,0x24,
		0x26,0x28,0x2A,0x2B,0x2D,0x2F,0x31,0x33,
		0x34,0x36,0x38,0x39,0x3B,0x3D,0x3E,0x40,
		0x42,0x43,0x45,0x47,0x48,0x4A,0x4B,0x4D,
		0x4F,0x50,0x52,0x53,0x55,0x56,0x58,0x59,
		0x5B,0x5D,0x5E,0x60,0x61,0x63,0x64,0x66,
		0x67,0x69,0x6A,0x6B,0x6D,0x6E,0x70,0x71,
		0x73,0x74,0x76,0x77,0x79,0x7A,0x7B,0x7D,
		0x7E,0x80,0x81,0x83,0x84,0x85,0x87,0x88,
		0x8A,0x8B,0x8C,0x8E,0x8F,0x90,0x92,0x93,
		0x95,0x96,0x97,0x99,0x9A,0x9B,0x9D,0x9E,
		0x9F,0xA1,0xA2,0xA3,0xA5,0xA6,0xA7,0xA9,
		0xAA,0xAB,0xAD,0xAE,0xAF,0xB1,0xB2,0xB3,
		0xB5,0xB6,0xB7,0xB9,0xBA,0xBB,0xBD,0xBE,
		0xBF,0xC0,0xC2,0xC3,0xC4,0xC6,0xC7,0xC8,
		0xC9,0xCB,0xCC,0xCD,0xCF,0xD0,0xD1,0xD2,
		0xD4,0xD5,0xD6,0xD7,0xD9,0xDA,0xDB,0xDC,
		0xDE,0xDF,0xE0,0xE1,0xE3,0xE4,0xE5,0xE6,
		0xE8,0xE9,0xEA,0xEB,0xEB,0xED,0xEE,0xEF,
		0xF0,0xF2,0xF3,0xF4,0xF5,0xF6,0xF8,0xF9,
		0xFA,0xFB,0xFD,0xFE,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
    },
    {
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,
        0x03,0x04,0x05,0x07,0x08,0x0A,0x0C,0x0E,
        0x10,0x12,0x14,0x16,0x18,0x1A,0x1C,0x1E,
        0x20,0x22,0x24,0x26,0x28,0x2A,0x2B,0x2D,
        0x2F,0x31,0x33,0x34,0x36,0x38,0x39,0x3B,
        0x3D,0x3E,0x40,0x42,0x43,0x45,0x47,0x48,
        0x4A,0x4B,0x4D,0x4F,0x50,0x52,0x53,0x55,
        0x56,0x58,0x59,0x5B,0x5D,0x5E,0x60,0x61,
        0x63,0x64,0x66,0x67,0x69,0x6A,0x6B,0x6D,
        0x6E,0x70,0x71,0x73,0x74,0x76,0x77,0x79,
        0x7A,0x7B,0x7D,0x7E,0x80,0x81,0x83,0x84,
        0x85,0x87,0x88,0x8A,0x8B,0x8C,0x8E,0x8F,
        0x90,0x92,0x93,0x95,0x96,0x97,0x99,0x9A,
        0x9B,0x9D,0x9E,0x9F,0xA1,0xA2,0xA3,0xA5,
        0xA6,0xA7,0xA9,0xAA,0xAB,0xAD,0xAE,0xAF,
        0xB1,0xB2,0xB3,0xB5,0xB6,0xB7,0xB9,0xBA,
        0xBB,0xBD,0xBE,0xBF,0xC0,0xC2,0xC3,0xC4,
        0xC6,0xC7,0xC8,0xC9,0xCB,0xCC,0xCD,0xCF,
        0xD0,0xD1,0xD2,0xD4,0xD5,0xD6,0xD7,0xD9,
        0xDA,0xDB,0xDC,0xDE,0xDF,0xE0,0xE1,0xE3,
        0xE4,0xE5,0xE6,0xE8,0xE9,0xEA,0xEB,0xED,
        0xEE,0xEF,0xF0,0xF2,0xF3,0xF4,0xF5,0xF6,
        0xF8,0xF9,0xFA,0xFB,0xFD,0xFE,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
    },
    {
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
        0x02,0x03,0x04,0x05,0x06,0x08,0x0A,0x0C,
        0x0E,0x10,0x12,0x14,0x16,0x19,0x1B,0x1D,
        0x1F,0x20,0x22,0x24,0x26,0x28,0x2A,0x2B,
        0x2D,0x2F,0x31,0x32,0x34,0x35,0x37,0x39,
        0x3A,0x3C,0x3D,0x3F,0x41,0x42,0x44,0x45,
        0x47,0x48,0x4A,0x4B,0x4D,0x4E,0x4F,0x51,
        0x52,0x54,0x55,0x57,0x58,0x59,0x5B,0x5C,
        0x5E,0x5F,0x60,0x62,0x63,0x64,0x66,0x67,
        0x68,0x6A,0x6B,0x6C,0x6E,0x6F,0x70,0x72,
        0x73,0x74,0x75,0x77,0x78,0x79,0x7B,0x7C,
        0x7D,0x7E,0x80,0x81,0x82,0x83,0x85,0x86,
        0x87,0x88,0x89,0x8B,0x8C,0x8D,0x8E,0x90,
        0x91,0x92,0x93,0x94,0x96,0x97,0x98,0x99,
        0x9A,0x9B,0x9D,0x9E,0x9F,0xA0,0xA1,0xA2,
        0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAB,0xAC,
        0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB4,0xB5,
        0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBD,0xBE,
        0xBF,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,
        0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
        0xD0,0xD1,0xD2,0xD3,0xD4,0xD6,0xD7,0xD8,
        0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,
        0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xEA,
        0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,
        0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,
        0xFB,0xFC,0xFD,0xFE,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
    },
    {
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,
		0x03,0x04,0x05,0x06,0x07,0x09,0x0B,0x0C,
		0x0E,0x10,0x12,0x14,0x16,0x18,0x1A,0x1C,
		0x1E,0x20,0x21,0x23,0x25,0x27,0x28,0x2A,
		0x2C,0x2D,0x2F,0x31,0x32,0x34,0x36,0x37,
		0x39,0x3B,0x3C,0x3E,0x3F,0x41,0x42,0x44,
		0x45,0x47,0x48,0x4A,0x4B,0x4D,0x4E,0x50,
		0x51,0x53,0x54,0x56,0x57,0x59,0x5A,0x5C,
		0x5D,0x5F,0x60,0x61,0x63,0x64,0x66,0x67,
		0x68,0x6A,0x6B,0x6D,0x6E,0x6F,0x71,0x72,
		0x73,0x75,0x76,0x78,0x79,0x7A,0x7C,0x7D,
		0x7E,0x80,0x81,0x82,0x84,0x85,0x86,0x88,
		0x89,0x8A,0x8B,0x8D,0x8E,0x8F,0x91,0x92,
		0x93,0x95,0x96,0x97,0x98,0x9A,0x9B,0x9C,
		0x9E,0x9F,0xA0,0xA1,0xA3,0xA4,0xA5,0xA6,
		0xA8,0xA9,0xAA,0xAB,0xAD,0xAE,0xAF,0xB0,
		0xB2,0xB3,0xB4,0xB5,0xB7,0xB8,0xB9,0xBA,
		0xBC,0xBD,0xBE,0xBF,0xC0,0xC2,0xC3,0xC4,
		0xC5,0xC7,0xC8,0xC9,0xCA,0xCB,0xCD,0xCE,
		0xCF,0xD0,0xD1,0xD3,0xD4,0xD5,0xD6,0xD7,
		0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xE0,0xE1,
		0xE2,0xE3,0xE4,0xE6,0xE7,0xE8,0xE9,0xEA,
		0xEB,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,
		0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFC,0xFD,
		0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
    }
};

static unsigned char LUT_G[][256] =
{
    {
        0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
        0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
        0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
        0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
        0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
        0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
        0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
        0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
        0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
        0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
        0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,
        0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
        0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
        0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
        0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
        0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
        0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
        0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
        0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,
        0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
        0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,
        0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
        0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,
        0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
        0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,
        0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
        0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,
        0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
        0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,
        0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
        0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,
        0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
    },
    {
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
        0x02,0x03,0x04,0x06,0x07,0x09,0x0B,0x0D,
        0x10,0x12,0x14,0x17,0x19,0x1B,0x1E,0x20,
        0x22,0x24,0x26,0x28,0x2A,0x2C,0x2E,0x30,
        0x32,0x33,0x35,0x37,0x39,0x3B,0x3C,0x3E,
        0x40,0x41,0x43,0x45,0x46,0x48,0x4A,0x4B,
        0x4D,0x4F,0x50,0x52,0x53,0x55,0x57,0x58,
        0x5A,0x5B,0x5D,0x5E,0x60,0x61,0x63,0x64,
        0x66,0x67,0x69,0x6A,0x6C,0x6D,0x6F,0x70,
        0x71,0x73,0x74,0x76,0x77,0x79,0x7A,0x7B,
        0x7D,0x7E,0x7F,0x81,0x82,0x84,0x85,0x86,
        0x88,0x89,0x8A,0x8C,0x8D,0x8E,0x90,0x91,
        0x92,0x94,0x95,0x96,0x98,0x99,0x9A,0x9C,
        0x9D,0x9E,0xA0,0xA1,0xA2,0xA3,0xA5,0xA6,
        0xA7,0xA8,0xAA,0xAB,0xAC,0xAE,0xAF,0xB0,
        0xB1,0xB3,0xB4,0xB5,0xB6,0xB8,0xB9,0xBA,
        0xBB,0xBC,0xBE,0xBF,0xC0,0xC1,0xC3,0xC4,
        0xC5,0xC6,0xC7,0xC9,0xCA,0xCB,0xCC,0xCD,
        0xCF,0xD0,0xD1,0xD2,0xD3,0xD5,0xD6,0xD7,
        0xD8,0xD9,0xDA,0xDC,0xDD,0xDE,0xDF,0xE0,
        0xE1,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,
        0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF3,
        0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFB,0xFC,
        0xFD,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
    },
    {
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
		0x02,0x03,0x04,0x05,0x07,0x08,0x0A,0x0C,
		0x0E,0x10,0x12,0x14,0x16,0x16,0x19,0x1B,
		0x1D,0x1F,0x21,0x23,0x25,0x27,0x28,0x2A,
		0x2C,0x2E,0x30,0x32,0x33,0x35,0x37,0x39,
		0x3A,0x3C,0x3E,0x40,0x41,0x43,0x45,0x46,
		0x48,0x4A,0x4B,0x4D,0x4F,0x50,0x52,0x53,
		0x55,0x57,0x58,0x5A,0x5B,0x5D,0x5F,0x60,
		0x62,0x63,0x65,0x66,0x68,0x69,0x6B,0x6C,
		0x6E,0x6F,0x71,0x72,0x74,0x75,0x77,0x78,
		0x7A,0x7B,0x7D,0x7E,0x80,0x81,0x83,0x84,
		0x86,0x87,0x88,0x8A,0x8B,0x8D,0x8E,0x90,
		0x91,0x92,0x94,0x95,0x97,0x98,0x99,0x9B,
		0x9C,0x9E,0x9F,0xA0,0xA2,0xA3,0xA5,0xA7,
		0xA9,0xAA,0xAB,0xAD,0xAE,0xB0,0xB1,0xB2,
		0xB4,0xB5,0xB6,0xB8,0xB9,0xBA,0xBC,0xBD,
		0xBE,0xC0,0xC1,0xC2,0xC4,0xC5,0xC6,0xC8,
		0xC9,0xCA,0xCC,0xCD,0xCE,0xD0,0xD1,0xD2,
		0xD4,0xD5,0xD6,0xD7,0xD9,0xDA,0xDB,0xDD,
		0xDE,0xDF,0xE1,0xE2,0xE3,0xE4,0xE6,0xE7,
		0xE8,0xE9,0xEB,0xEC,0xED,0xEF,0xF0,0xF1,
		0xF2,0xF4,0xF5,0xF6,0xF7,0xF9,0xFA,0xFB,
		0xFC,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
    },
    {
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x07,
		0x08,0x0A,0x0C,0x0E,0x10,0x12,0x14,0x16,
		0x18,0x1A,0x1C,0x1E,0x20,0x22,0x24,0x26,
		0x28,0x2A,0x2B,0x2D,0x2F,0x31,0x33,0x34,
		0x36,0x38,0x39,0x3B,0x3D,0x3E,0x40,0x42,
		0x43,0x45,0x47,0x48,0x4A,0x4B,0x4D,0x4F,
		0x50,0x52,0x53,0x55,0x56,0x58,0x59,0x5B,
		0x5D,0x5E,0x60,0x61,0x63,0x64,0x66,0x67,
		0x69,0x6A,0x6B,0x6D,0x6E,0x70,0x71,0x73,
		0x74,0x76,0x77,0x79,0x7A,0x7B,0x7D,0x7E,
		0x80,0x81,0x83,0x84,0x85,0x87,0x88,0x8A,
		0x8B,0x8C,0x8E,0x8F,0x90,0x92,0x93,0x95,
		0x96,0x97,0x99,0x9A,0x9B,0x9D,0x9E,0x9F,
		0xA1,0xA2,0xA3,0xA5,0xA6,0xA7,0xA9,0xAA,
		0xAB,0xAD,0xAE,0xAF,0xB1,0xB2,0xB3,0xB5,
		0xB6,0xB7,0xB9,0xBA,0xBB,0xBD,0xBE,0xBF,
		0xC0,0xC2,0xC3,0xC4,0xC6,0xC7,0xC8,0xC9,
		0xCB,0xCC,0xCD,0xCF,0xD0,0xD1,0xD2,0xD4,
		0xD5,0xD6,0xD7,0xD9,0xDA,0xDB,0xDC,0xDF,
		0xE0,0xE1,0xE3,0xE4,0xE5,0xE6,0xE8,0xE9,
		0xEA,0xEB,0xED,0xEE,0xEF,0xF0,0xF2,0xF3,
		0xF4,0xF5,0xF6,0xF8,0xF9,0xFA,0xFB,0xFD,
		0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
	},
	{
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,
		0x04,0x05,0x07,0x08,0x0A,0x0C,0x0E,0x10,
		0x12,0x14,0x16,0x18,0x1A,0x1C,0x1E,0x20,
		0x22,0x24,0x26,0x28,0x2A,0x2B,0x2D,0x2F,
		0x31,0x33,0x34,0x36,0x38,0x39,0x3B,0x3D,
		0x3E,0x40,0x42,0x43,0x45,0x47,0x48,0x4A,
		0x4B,0x4D,0x4F,0x50,0x52,0x53,0x55,0x56,
		0x58,0x59,0x5B,0x5D,0x5E,0x60,0x61,0x63,
		0x64,0x66,0x67,0x69,0x6A,0x6B,0x6D,0x6E,
		0x70,0x71,0x73,0x74,0x76,0x77,0x79,0x7A,
		0x7B,0x7D,0x7E,0x80,0x81,0x83,0x84,0x85,
		0x87,0x88,0x8A,0x8B,0x8C,0x8E,0x8F,0x90,
		0x92,0x93,0x95,0x96,0x97,0x99,0x9A,0x9B,
		0x9D,0x9E,0x9F,0xA1,0xA2,0xA3,0xA5,0xA6,
		0xA7,0xA9,0xAA,0xAB,0xAD,0xAE,0xAF,0xB1,
		0xB2,0xB3,0xB5,0xB6,0xB7,0xB9,0xBA,0xBB,
		0xBD,0xBE,0xBF,0xC0,0xC2,0xC3,0xC4,0xC6,
		0xC7,0xC8,0xC9,0xCB,0xCC,0xCD,0xCF,0xD0,
		0xD1,0xD2,0xD4,0xD5,0xD6,0xD7,0xD9,0xDA,
		0xDB,0xDC,0xDE,0xDF,0xE0,0xE1,0xE3,0xE5,
		0xE6,0xE8,0xE9,0xEA,0xEB,0xED,0xEE,0xEF,
		0xF0,0xF2,0xF3,0xF4,0xF5,0xF6,0xF8,0xF9,
		0xFA,0xFB,0xFD,0xFE,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
    },
    {
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x01,0x02,0x03,0x04,0x05,0x07,0x08,0x0A,
        0x0C,0x0E,0x10,0x12,0x14,0x16,0x18,0x1A,
        0x1C,0x1E,0x20,0x22,0x24,0x26,0x28,0x2A,
        0x2B,0x2D,0x2F,0x31,0x33,0x34,0x36,0x38,
        0x39,0x3B,0x3D,0x3E,0x40,0x42,0x43,0x45,
        0x47,0x48,0x4A,0x4B,0x4D,0x4F,0x50,0x52,
        0x53,0x55,0x56,0x58,0x59,0x5B,0x5D,0x5E,
        0x60,0x61,0x63,0x64,0x66,0x67,0x69,0x6A,
        0x6B,0x6D,0x6E,0x70,0x71,0x73,0x74,0x76,
        0x77,0x79,0x7A,0x7B,0x7D,0x7E,0x80,0x81,
        0x83,0x84,0x85,0x87,0x88,0x8A,0x8B,0x8C,
        0x8E,0x8F,0x90,0x92,0x93,0x95,0x96,0x97,
        0x99,0x9A,0x9B,0x9D,0x9E,0x9F,0xA1,0xA2,
        0xA3,0xA5,0xA6,0xA7,0xA9,0xAA,0xAB,0xAD,
        0xAE,0xAF,0xB1,0xB2,0xB3,0xB5,0xB6,0xB7,
        0xB9,0xBA,0xBB,0xBD,0xBE,0xBF,0xC0,0xC2,
        0xC3,0xC4,0xC6,0xC7,0xC8,0xC9,0xCB,0xCC,
        0xCD,0xCF,0xD0,0xD1,0xD2,0xD4,0xD5,0xD6,
        0xD7,0xD9,0xDA,0xDB,0xDC,0xDE,0xDF,0xE0,
        0xE3,0xE4,0xE5,0xE6,0xE8,0xE9,0xEA,0xEB,
        0xED,0xEE,0xEF,0xF0,0xF2,0xF3,0xF4,0xF5,
        0xF6,0xF8,0xF9,0xFA,0xFB,0xFD,0xFE,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
    },
    {
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,
        0x03,0x04,0x05,0x07,0x08,0x0A,0x0C,0x0E,
        0x10,0x12,0x14,0x16,0x18,0x18,0x1A,0x1C,
        0x1E,0x20,0x22,0x24,0x26,0x27,0x29,0x2B,
        0x2C,0x2E,0x30,0x31,0x33,0x35,0x36,0x38,
        0x39,0x3B,0x3C,0x3E,0x40,0x41,0x43,0x44,
        0x45,0x47,0x48,0x4A,0x4B,0x4D,0x4E,0x50,
        0x51,0x52,0x54,0x55,0x56,0x58,0x59,0x5B,
        0x5C,0x5D,0x5F,0x60,0x61,0x63,0x64,0x65,
        0x67,0x68,0x69,0x6A,0x6C,0x6D,0x6E,0x70,
        0x71,0x72,0x73,0x75,0x76,0x77,0x78,0x7A,
        0x7B,0x7C,0x7D,0x7E,0x80,0x81,0x82,0x83,
        0x85,0x86,0x87,0x88,0x89,0x8A,0x8C,0x8D,
        0x8E,0x8F,0x90,0x92,0x93,0x94,0x95,0x96,
        0x97,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
        0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,
        0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,
        0xB2,0xB3,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,
        0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0xC2,0xC4,
        0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,
        0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD4,0xD5,
        0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,
        0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,
        0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,
        0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,
        0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,
        0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
    },
    {	// 7
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,
		0x03,0x04,0x05,0x06,0x07,0x09,0x0B,0x0C,
		0x0E,0x10,0x12,0x14,0x16,0x18,0x1A,0x1C,
		0x1E,0x20,0x21,0x23,0x25,0x27,0x28,0x2A,
		0x2C,0x2D,0x2F,0x31,0x32,0x34,0x36,0x37,
		0x39,0x3B,0x3C,0x3E,0x3F,0x41,0x42,0x44,
		0x45,0x47,0x48,0x4A,0x4B,0x4D,0x4E,0x50,
		0x51,0x53,0x54,0x56,0x57,0x59,0x5A,0x5C,
		0x5D,0x5F,0x60,0x61,0x63,0x64,0x66,0x67,
		0x68,0x6A,0x6B,0x6D,0x6E,0x6F,0x71,0x72,
		0x73,0x75,0x76,0x78,0x79,0x7A,0x7C,0x7D,
		0x7E,0x80,0x81,0x82,0x84,0x85,0x86,0x88,
		0x89,0x8A,0x8B,0x8D,0x8E,0x8F,0x91,0x92,
		0x93,0x95,0x96,0x97,0x98,0x9A,0x9B,0x9C,
		0x9E,0x9F,0xA0,0xA1,0xA3,0xA4,0xA5,0xA6,
		0xA8,0xA9,0xAA,0xAB,0xAD,0xAE,0xAF,0xB0,
		0xB2,0xB3,0xB4,0xB5,0xB7,0xB8,0xB9,0xBA,
		0xBC,0xBD,0xBE,0xBF,0xC0,0xC2,0xC3,0xC4,
		0xC5,0xC7,0xC8,0xC9,0xCA,0xCB,0xCD,0xCE,
		0xCF,0xD0,0xD1,0xD3,0xD4,0xD5,0xD6,0xD7,
		0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xE0,0xE1,
		0xE2,0xE3,0xE4,0xE6,0xE7,0xE8,0xE9,0xEA,
		0xEB,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,
		0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFC,0xFD,
		0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
    }
};

static unsigned char LUT_B[][256] =
{
    {
        0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
        0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
        0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
        0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
        0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
        0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
        0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
        0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
        0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
        0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
        0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,
        0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
        0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
        0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
        0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
        0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
        0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
        0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
        0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,
        0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
        0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,
        0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
        0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,
        0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
        0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,
        0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
        0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,
        0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
        0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,
        0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
        0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,
        0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
    },
    {
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
        0x02,0x03,0x04,0x06,0x07,0x09,0x0B,0x0D,
        0x10,0x12,0x14,0x17,0x19,0x1B,0x1E,0x20,
        0x22,0x24,0x26,0x28,0x2A,0x2C,0x2E,0x30,
        0x32,0x33,0x35,0x37,0x39,0x3B,0x3C,0x3E,
        0x40,0x41,0x43,0x45,0x46,0x48,0x4A,0x4B,
        0x4D,0x4F,0x50,0x52,0x53,0x55,0x57,0x58,
        0x5A,0x5B,0x5D,0x5E,0x60,0x61,0x63,0x64,
        0x66,0x67,0x69,0x6A,0x6C,0x6D,0x6F,0x70,
        0x71,0x73,0x74,0x76,0x77,0x79,0x7A,0x7B,
        0x7D,0x7E,0x7F,0x81,0x82,0x84,0x85,0x86,
        0x88,0x89,0x8A,0x8C,0x8D,0x8E,0x90,0x91,
        0x92,0x94,0x95,0x96,0x98,0x99,0x9A,0x9C,
        0x9D,0x9E,0xA0,0xA1,0xA2,0xA3,0xA5,0xA6,
        0xA7,0xA8,0xAA,0xAB,0xAC,0xAE,0xAF,0xB0,
        0xB1,0xB3,0xB4,0xB5,0xB6,0xB8,0xB9,0xBA,
        0xBB,0xBC,0xBE,0xBF,0xC0,0xC1,0xC3,0xC4,
        0xC5,0xC6,0xC7,0xC9,0xCA,0xCB,0xCC,0xCD,
        0xCF,0xD0,0xD1,0xD2,0xD3,0xD5,0xD6,0xD7,
        0xD8,0xD9,0xDA,0xDC,0xDD,0xDE,0xDF,0xE0,
        0xE1,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,
        0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF3,
        0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFB,0xFC,
        0xFD,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
    },
    {
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
		0x02,0x03,0x04,0x05,0x07,0x08,0x0A,0x0C,
		0x0E,0x10,0x12,0x14,0x16,0x16,0x19,0x1B,
		0x1D,0x1F,0x21,0x23,0x25,0x27,0x28,0x2A,
		0x2C,0x2E,0x30,0x32,0x33,0x35,0x37,0x39,
		0x3A,0x3C,0x3E,0x40,0x41,0x43,0x45,0x46,
		0x48,0x4A,0x4B,0x4D,0x4F,0x50,0x52,0x53,
		0x55,0x57,0x58,0x5A,0x5B,0x5D,0x5F,0x60,
		0x62,0x63,0x65,0x66,0x68,0x69,0x6B,0x6C,
		0x6E,0x6F,0x71,0x72,0x74,0x75,0x77,0x78,
		0x7A,0x7B,0x7D,0x7E,0x80,0x81,0x83,0x84,
		0x86,0x87,0x88,0x8A,0x8B,0x8D,0x8E,0x90,
		0x91,0x92,0x94,0x95,0x97,0x98,0x99,0x9B,
		0x9C,0x9E,0x9F,0xA0,0xA2,0xA3,0xA5,0xA7,
		0xA9,0xAA,0xAB,0xAD,0xAE,0xB0,0xB1,0xB2,
		0xB4,0xB5,0xB6,0xB8,0xB9,0xBA,0xBC,0xBD,
		0xBE,0xC0,0xC1,0xC2,0xC4,0xC5,0xC6,0xC8,
		0xC9,0xCA,0xCC,0xCD,0xCE,0xD0,0xD1,0xD2,
		0xD4,0xD5,0xD6,0xD7,0xD9,0xDA,0xDB,0xDD,
		0xDE,0xDF,0xE1,0xE2,0xE3,0xE4,0xE6,0xE7,
		0xE8,0xE9,0xEB,0xEC,0xED,0xEF,0xF0,0xF1,
		0xF2,0xF4,0xF5,0xF6,0xF7,0xF9,0xFA,0xFB,
		0xFC,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
    },
    {
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x01,0x02,0x03,0x04,0x05,0x07,0x08,
		0x0A,0x0C,0x0E,0x10,0x12,0x14,0x16,0x18,
		0x1A,0x1C,0x1E,0x20,0x22,0x24,0x26,0x28,
		0x2A,0x2B,0x2D,0x2F,0x31,0x33,0x34,0x36,
		0x38,0x39,0x3B,0x3D,0x3E,0x40,0x42,0x43,
		0x45,0x47,0x48,0x4A,0x4B,0x4D,0x4F,0x50,
		0x52,0x53,0x55,0x56,0x58,0x59,0x5B,0x5D,
		0x5E,0x60,0x61,0x63,0x64,0x66,0x67,0x69,
		0x6A,0x6B,0x6D,0x6E,0x70,0x71,0x73,0x74,
		0x76,0x77,0x79,0x7A,0x7B,0x7D,0x7E,0x80,
		0x81,0x83,0x84,0x85,0x87,0x88,0x8A,0x8B,
		0x8C,0x8E,0x8F,0x90,0x92,0x93,0x95,0x96,
		0x97,0x99,0x9A,0x9B,0x9D,0x9E,0x9F,0xA1,
		0xA2,0xA3,0xA5,0xA6,0xA7,0xA9,0xAA,0xAB,
		0xAD,0xAE,0xAF,0xB1,0xB2,0xB3,0xB5,0xB6,
		0xB7,0xB9,0xBA,0xBB,0xBD,0xBE,0xBF,0xC0,
		0xC2,0xC3,0xC4,0xC6,0xC7,0xC8,0xC9,0xCB,
		0xCC,0xCD,0xCF,0xD0,0xD1,0xD2,0xD4,0xD5,
		0xD6,0xD7,0xD9,0xDA,0xDB,0xDC,0xDE,0xDF,
		0xE0,0xE1,0xE3,0xE4,0xE5,0xE6,0xE8,0xE9,
		0xEA,0xEB,0xED,0xEE,0xEF,0xF0,0xF2,0xF3,
		0xF4,0xF5,0xF6,0xF8,0xF9,0xFA,0xFB,0xFD,
		0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
	},
	{
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,
		0x05,0x07,0x08,0x0A,0x0C,0x0E,0x10,0x12,
		0x14,0x16,0x18,0x1A,0x1C,0x1E,0x20,0x22,
		0x24,0x26,0x28,0x2A,0x2B,0x2D,0x2F,0x31,
		0x33,0x34,0x36,0x38,0x39,0x3B,0x3D,0x3E,
		0x40,0x42,0x43,0x45,0x47,0x48,0x4A,0x4B,
		0x4D,0x4F,0x50,0x52,0x53,0x55,0x56,0x58,
		0x59,0x5B,0x5D,0x5E,0x60,0x61,0x63,0x64,
		0x66,0x67,0x69,0x6A,0x6B,0x6D,0x6E,0x70,
		0x71,0x73,0x74,0x76,0x77,0x79,0x7A,0x7B,
		0x7D,0x7E,0x80,0x81,0x83,0x84,0x85,0x87,
		0x88,0x8A,0x8B,0x8C,0x8E,0x8F,0x90,0x92,
		0x93,0x95,0x96,0x97,0x99,0x9A,0x9B,0x9D,
		0x9E,0x9F,0xA1,0xA2,0xA3,0xA5,0xA6,0xA7,
		0xA9,0xAA,0xAB,0xAD,0xAE,0xAF,0xB1,0xB2,
		0xB3,0xB5,0xB6,0xB7,0xB9,0xBA,0xBB,0xBD,
		0xBE,0xBF,0xC0,0xC2,0xC3,0xC4,0xC6,0xC7,
		0xC8,0xC9,0xCB,0xCC,0xCD,0xCF,0xD0,0xD1,
		0xD2,0xD4,0xD5,0xD6,0xD7,0xD9,0xDA,0xDB,
		0xDC,0xDE,0xDF,0xE0,0xE1,0xE3,0xE4,0xE5,
		0xE6,0xE8,0xE9,0xEA,0xEB,0xED,0xEE,0xEF,
		0xF0,0xF2,0xF3,0xF4,0xF5,0xF6,0xF8,0xF9,
		0xFA,0xFB,0xFD,0xFE,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
    },
    {
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
        0x02,0x03,0x04,0x05,0x07,0x08,0x0A,0x0C,
        0x0E,0x10,0x12,0x14,0x16,0x16,0x18,0x1A,
        0x1C,0x1E,0x20,0x22,0x24,0x26,0x28,0x2A,
        0x2B,0x2D,0x2F,0x31,0x33,0x34,0x36,0x38,
        0x39,0x3B,0x3D,0x3E,0x40,0x42,0x43,0x45,
        0x47,0x48,0x4A,0x4B,0x4D,0x4F,0x50,0x52,
        0x53,0x55,0x56,0x58,0x59,0x5B,0x5D,0x5E,
        0x60,0x61,0x63,0x64,0x66,0x67,0x69,0x6A,
        0x6B,0x6D,0x6E,0x70,0x71,0x73,0x74,0x76,
        0x77,0x79,0x7A,0x7B,0x7D,0x7E,0x80,0x81,
        0x83,0x84,0x85,0x87,0x88,0x8A,0x8B,0x8C,
        0x8E,0x8F,0x90,0x92,0x93,0x95,0x96,0x97,
        0x99,0x9A,0x9B,0x9D,0x9E,0x9F,0xA1,0xA3,
        0xA5,0xA6,0xA7,0xA9,0xAA,0xAB,0xAD,0xAE,
        0xAF,0xB1,0xB2,0xB3,0xB5,0xB6,0xB7,0xB9,
        0xBA,0xBB,0xBD,0xBE,0xBF,0xC0,0xC2,0xC3,
        0xC4,0xC6,0xC7,0xC8,0xC9,0xCB,0xCC,0xCD,
        0xCF,0xD0,0xD1,0xD2,0xD4,0xD5,0xD6,0xD7,
        0xD9,0xDA,0xDB,0xDC,0xDE,0xDF,0xE0,0xE1,
        0xE3,0xE4,0xE5,0xE6,0xE8,0xE9,0xEA,0xEB,
        0xED,0xEE,0xEF,0xF0,0xF2,0xF3,0xF4,0xF5,
        0xF6,0xF8,0xF9,0xFA,0xFB,0xFD,0xFE,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
    },
    {
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,
        0x04,0x05,0x07,0x08,0x0A,0x0C,0x0E,0x10,
        0x12,0x14,0x16,0x18,0x1A,0x1C,0x1E,0x20,
        0x22,0x24,0x26,0x27,0x29,0x2B,0x2C,0x2E,
        0x30,0x31,0x33,0x35,0x36,0x38,0x39,0x3B,
        0x3C,0x3E,0x40,0x41,0x43,0x44,0x45,0x47,
        0x48,0x4B,0x4D,0x4E,0x50,0x51,0x52,0x54,
        0x55,0x56,0x58,0x59,0x5B,0x5C,0x5D,0x5F,
        0x60,0x61,0x63,0x64,0x65,0x67,0x68,0x69,
        0x6A,0x6C,0x6D,0x6E,0x70,0x71,0x72,0x73,
        0x75,0x76,0x77,0x78,0x7A,0x7B,0x7C,0x7D,
        0x7E,0x80,0x81,0x82,0x83,0x85,0x86,0x87,
        0x88,0x89,0x8A,0x8C,0x8D,0x8E,0x8F,0x90,
        0x92,0x93,0x94,0x95,0x96,0x96,0x97,0x99,
        0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xA1,0xA2,
        0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xAA,0xAB,
        0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,
        0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,
        0xBD,0xBE,0xBF,0xC0,0xC2,0xC3,0xC4,0xC5,
        0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,
        0xCE,0xCF,0xD0,0xD1,0xD2,0xD4,0xD5,0xD6,
        0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,
        0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,
        0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,
        0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,
        0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,
        0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
    },
    {
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,
        0x03,0x04,0x05,0x06,0x07,0x09,0x0B,0x0C,
        0x0E,0x10,0x12,0x14,0x16,0x18,0x1A,0x1C,
        0x1E,0x20,0x21,0x23,0x25,0x27,0x28,0x2A,
        0x2C,0x2D,0x2F,0x31,0x32,0x34,0x36,0x37,
        0x39,0x3B,0x3C,0x3E,0x3F,0x41,0x42,0x44,
        0x45,0x47,0x48,0x4A,0x4B,0x4D,0x4E,0x50,
        0x51,0x53,0x54,0x56,0x57,0x59,0x5A,0x5C,
        0x5D,0x5F,0x60,0x61,0x63,0x64,0x66,0x67,
        0x68,0x6A,0x6B,0x6D,0x6E,0x6F,0x71,0x72,
        0x73,0x75,0x76,0x78,0x79,0x7A,0x7C,0x7D,
        0x7E,0x80,0x81,0x82,0x84,0x85,0x86,0x88,
        0x89,0x8A,0x8B,0x8D,0x8E,0x8F,0x91,0x92,
        0x93,0x95,0x96,0x97,0x98,0x9A,0x9B,0x9C,
        0x9E,0x9F,0xA0,0xA1,0xA3,0xA4,0xA5,0xA6,
        0xA8,0xA9,0xAA,0xAB,0xAD,0xAE,0xAF,0xB0,
        0xB2,0xB3,0xB4,0xB5,0xB7,0xB8,0xB9,0xBA,
        0xBC,0xBD,0xBE,0xBF,0xC0,0xC2,0xC3,0xC4,
        0xC5,0xC7,0xC8,0xC9,0xCA,0xCB,0xCD,0xCE,
        0xCF,0xD0,0xD1,0xD3,0xD4,0xD5,0xD6,0xD7,
        0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xE0,0xE1,
        0xE2,0xE3,0xE4,0xE6,0xE7,0xE8,0xE9,0xEA,
        0xEB,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,
        0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFC,0xFD,
        0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
    }
};
//// profile array ////

typedef struct
{
	int  productID; // USB PID
    char		productName[50]; // ESCI/2 procduct name
	char 		deviceID[50]; // device ID (same as bonjour mdl name)
    int  lutID; // look up table no
}epsonds_profile_map;

const  epsonds_profile_map epsonds_models_predefined[] = {
  {0x0145, "DS-5500","DS-5500", 7},
  {0x0145, "DS-6500","DS-6500", 7},
  {0x0145, "DS-7500","DS-7500", 7},
  {0x0146, "DS-50000","DS-50000", 7},
  {0x0146, "DS-60000","DS-60000", 7},
  {0x0146, "DS-70000","DS-70000", 7},
  {0x014C, "DS-510","DS-510", 7},
  {0x0150, "DS-560","DS-560", 7},
  {0x0152, "DS-40","DS-40", 7},
  {0x014D, "DS-760","DS-760", 7},
  {0x014D, "DS-860","DS-860", 7},
  {0x0154, "DS-520","DS-520", 7},
  {0x08BC, "PID 08BC","PX-M7050 Series", 7},
  {0x08BC, "PID 08BC","WF-8510 Series", 7},
  {0x08BC, "PID 08BC","WF-8590 Series", 7},
  {0x08CC, "PID 08CC","PX-M7050FX Series", 7},
  {0x08CC, "PID 08CC","WF-R8590 Series", 7},
  {0x0165, "DS-410","DS-410", 7},
  {0x016C, "ES-50","ES-50", 6},
  {0x0160, "DS-70","DS-70", 6},
  {0x016D, "ES-55R","ES-55R", 6},
  {0x018C, "RR-60","RR-60", 6},
  {0x016E, "ES-60W","ES-60W", 6},
  {0x0166, "DS-80W","DS-80W", 6},
  {0x016F, "ES-65WR","ES-65WR", 6},
  {0x018B, "RR-70W","RR-70W", 6},
  {0x016E, "ES-60WW","ES-60WW", 6},
  {0x016E, "ES-60WB","ES-60WB", 6},
  {0x015C, "DS-1630","DS-1630", 4},
  {0x015D, "DS-1610","DS-1610", 4},
  {0x015E, "DS-1660W","DS-1660W", 4},
  {0x0159, "DS-310","DS-310", 5},
  {0x0159, "ES-200","ES-200", 5},
  {0x0162, "DS-320","DS-320", 5},
  {0x015A, "DS-360W","DS-360W", 5},
  {0x015A, "ES-300W","ES-300W", 5},
  {0x0177, "ES-300WR","ES-300WR", 5},
  {0x0181, "ES-400II","ES-400II", 2},
  {0x0183, "DS-535II","DS-535II", 2},
  {0x0184, "DS-531","DS-531", 2},
  {0x0182, "DS-530II","DS-530II", 2},
  {0x0185, "ES-500WII","ES-500WII", 2},
  {0x0188, "DS-571W","DS-571W", 2},
  {0x0187, "DS-575WII","DS-575WII", 2},
  {0x0186, "DS-570WII","DS-570WII", 2},
  {0x017F, "ES-580W","ES-580W", 2},
  {0x0180, "RR-600W","RR-600W", 2},
  {0x0167, "DS-535","DS-535", 2},
  {0x017A, "DS-535H","DS-535H", 2},
  {0x0156, "ES-400","ES-400", 2},
  {0x0155, "DS-530","DS-530", 2},
  {0x016B, "FF-680W","FF-680W", 2},
  {0x0157, "DS-570W","DS-570W", 2},
  {0x0157, "ES-500W","ES-500W", 2},
  {0x0169, "DS-575W","DS-575W", 2},
  {0x0176, "ES-500WR","ES-500WR", 2},
  {0x114E, "PID 114E","EW-052A Series", 7},
  {0x114E, "PID 114E","XP-2100 Series", 7},
  {0x1135, "PID 1135","ET-2700 Series", 7},
  {0x1135, "PID 1135","L4150 Series", 7},
  {0x114A, "PID 114A","ET-M2140 Series", 7},
  {0x114A, "PID 114A","M2140 Series", 7},
  {0x114F, "PID 114F","ET-M3140 Series", 7},
  {0x114F, "PID 114F","M3140 Series", 7},
  {0x1143, "PID 1143","L3150 Series", 7},
  {0x1143, "PID 1143","ET-2710 Series", 7},
  {0x118A, "PID 118A","ET-2810 Series", 7},
  {0x118A, "PID 118A","L3250 Series", 7},
  {0x119B, "PID 119B","XP-2150 Series", 7},
  {0x11B1, "PID 11B1","XP-2200 Series", 7},
  {0x00, "","", 0x00 }
};

typedef struct
{
  epsonds_profile_map *array;
  int used;
  int size;
}epsonds_profile_map_array;


static epsonds_profile_map_array stProfileMapArray;

static void insert_profile_map(epsonds_profile_map_array *a, epsonds_profile_map element);

static void init_profile_maps(epsonds_profile_map_array *a, size_t initialSize) {
  a->array = malloc(initialSize * sizeof(epsonds_profile_map));
  a->used = 0;
  a->size = initialSize;

   for (int i = 0; epsonds_models_predefined[i].productID != 0; i++) {

		//DBG(6, "epsonds_models_predefined[i].productID         = %x\n", epsonds_models_predefined[i].productID );

	   insert_profile_map(a, epsonds_models_predefined[i]);
   }
}

static void insert_profile_map(epsonds_profile_map_array *a, epsonds_profile_map element) {
  if (a->used == a->size) {
    a->size *= 2;
    a->array = realloc(a->array, a->size * sizeof(epsonds_profile_map));
  }
  a->array[a->used++] = element;
}

static void free_profile_maps(epsonds_profile_map_array *a) {
  free(a->array);
  a->array = NULL;
  a->used = a->size = 0;
}
/////////////////////////


struct mode_param mode_params[] = {
	{0, 0x00, 0x30, 1},
	{0, 0x00, 0x30, 8},
	{1, 0x02, 0x00, 8},
	{0, 0x00, 0x30, 1}
};

static SANE_String_Const mode_list[] = {
	SANE_VALUE_SCAN_MODE_LINEART,
	SANE_VALUE_SCAN_MODE_GRAY,
	SANE_VALUE_SCAN_MODE_COLOR,
	NULL
};


/* Define the different scan sources */

#define STRING_FLATBED SANE_I18N("Flatbed")
#define STRING_ADFFRONT SANE_I18N("ADF Front")
#define STRING_ADFDUPLEX SANE_I18N("ADF Duplex")

/* order will be fixed: fb, adf, tpu */
SANE_String_Const source_list[] = {
	NULL,
	NULL,
	NULL,
	NULL
};

/*
 * List of pointers to devices - will be dynamically allocated depending
 * on the number of devices found.
 */
static const SANE_Device **devlist;

/* Some utility functions */

static size_t
max_string_size(const SANE_String_Const strings[])
{
	size_t size, max_size = 0;
	int i;

	for (i = 0; strings[i]; i++) {
		size = strlen(strings[i]) + 1;
		if (size > max_size)
			max_size = size;
	}
	return max_size;
}

static SANE_Status attach_one_usb(SANE_String_Const devname);
static SANE_Status attach_one_net(SANE_String_Const devname);
static SANE_Status acquire_jpeg_data(epsonds_scanner* s);
static SANE_Status acquire_and_decode_jpeg_data(epsonds_scanner* s);
static SANE_Status acquire_raw_data(epsonds_scanner* s);

static void
print_params(const SANE_Parameters params)
{
	DBG(6, "params.format          = %d\n", params.format);
	DBG(6, "params.last_frame      = %d\n", params.last_frame);
	DBG(6, "params.bytes_per_line  = %d\n", params.bytes_per_line);
	DBG(6, "params.pixels_per_line = %d\n", params.pixels_per_line);
	DBG(6, "params.lines           = %d\n", params.lines);
	DBG(6, "params.depth           = %d\n", params.depth);
}

static void
close_scanner(epsonds_scanner *s)
{
	DBG(7, "%s: fd = %d\n", __func__, s->fd);

	if (s->scanning)
	{
		sane_cancel(s);
	}

	if (s->fd == -1)
		goto free;

	if (s->locked) {
		DBG(7, " unlocking scanner\n");
		esci2_fin(s);
	}

	if (s->hw->connection == SANE_EPSONDS_NET) {
		epsonds_net_unlock(s);
		sanei_tcp_close(s->fd);
	} else if (s->hw->connection == SANE_EPSONDS_USB) {
		sanei_usb_close(s->fd);
	}

free:

	free(s->front.ring);
	free(s->back.ring);
	free(s->line_buffer);
	free(s);

	DBG(7, "%s: ZZZ\n", __func__);
}

static SANE_Status
open_scanner(epsonds_scanner *s)
{
	SANE_Status status = SANE_STATUS_INVAL;

	DBG(7, "%s: %s\n", __func__, s->hw->sane.name);

	if (s->fd != -1) {
		DBG(5, "scanner is already open: fd = %d\n", s->fd);
		return SANE_STATUS_GOOD;	/* no need to open the scanner */
	}

	if (s->hw->connection == SANE_EPSONDS_NET) {
		unsigned char buf[5];

		/* device name has the form net:ipaddr */
		status = sanei_tcp_open(&s->hw->name[4], 1865, &s->fd);
		if (status == SANE_STATUS_GOOD) {

			ssize_t read;
			struct timeval tv;

			tv.tv_sec = 5;
			tv.tv_usec = 0;

			setsockopt(s->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,  sizeof(tv));

			s->netlen = 0;

			DBG(32, "awaiting welcome message\n");

			/* the scanner sends a kind of welcome msg */
			// XXX check command type, answer to connect is 0x80
			read = eds_recv(s, buf, 5, &status);
			if (read != 5) {
				sanei_tcp_close(s->fd);
				s->fd = -1;
				return SANE_STATUS_IO_ERROR;
			}

			DBG(32, "welcome message received, locking the scanner...\n");

			/* lock the scanner for use by sane */
			status = epsonds_net_lock(s);
			if (status != SANE_STATUS_GOOD) {
				DBG(1, "%s cannot lock scanner: %s\n", s->hw->sane.name,
					sane_strstatus(status));

				sanei_tcp_close(s->fd);
				s->fd = -1;

				return status;
			}

			DBG(32, "scanner locked\n");
		}

	} else if (s->hw->connection == SANE_EPSONDS_USB) {
		status = sanei_usb_open(s->hw->sane.name, &s->fd);

		if (status == SANE_STATUS_GOOD) {
			sanei_usb_set_timeout(USB_TIMEOUT);
		}

	} else {
		DBG(1, "unknown connection type: %d\n", s->hw->connection);
	}

	if (status == SANE_STATUS_ACCESS_DENIED) {
		DBG(1, "please check that you have permissions on the device.\n");
		DBG(1, "if this is a multi-function device with a printer,\n");
		DBG(1, "disable any conflicting driver (like usblp).\n");
	}

	if (status != SANE_STATUS_GOOD)
		DBG(1, "%s open failed: %s\n",
			s->hw->sane.name,
			sane_strstatus(status));
	else
		DBG(5, " opened correctly\n");

	return status;
}

static int num_devices;			/* number of scanners attached to backend */
static epsonds_device *first_dev;	/* first EPSON scanner in list */

static struct epsonds_scanner *
scanner_create(struct epsonds_device *dev, SANE_Status *status)
{
	struct epsonds_scanner *s;
	s = malloc(sizeof(struct epsonds_scanner));
	if (s == NULL) {
		*status = SANE_STATUS_NO_MEM;
		return NULL;
	}

	/* clear verything */
	memset(s, 0x00, sizeof(struct epsonds_scanner));

	s->fd = -1;
	s->hw = dev;

	return s;
}

static struct epsonds_scanner *
device_detect(const char *name, int type, SANE_Status *status)
{
	struct epsonds_scanner *s;
	struct epsonds_device *dev;

	DBG(1, "%s, %s, type: %d\n", __func__, name, type);

	/* try to find the device in our list */
	for (dev = first_dev; dev; dev = dev->next) {

		if (strcmp(dev->sane.name, name) == 0) {

			DBG(1, " found cached device\n");

			// the device might have been just probed, sleep a bit.
			if (dev->connection == SANE_EPSONDS_NET) {
				sleep(1);
			}

			return scanner_create(dev, status);
		}
	}

	/* not found, create new if valid */
	if (type == SANE_EPSONDS_NODEV) {
		*status = SANE_STATUS_INVAL;
		return NULL;
	}

	/* alloc and clear our device structure */
	dev = malloc(sizeof(*dev));
	if (!dev) {
		*status = SANE_STATUS_NO_MEM;
		return NULL;
	}
	memset(dev, 0x00, sizeof(struct epsonds_device));

	s = scanner_create(dev, status);
	if (s == NULL)
		return NULL;

	dev->connection = type;
	dev->model = strdup("(undetermined)");
	dev->name = strdup(name);

	dev->sane.name = dev->name;
	dev->sane.vendor = "Epson";
	dev->sane.model = dev->model;
	dev->sane.type = "ESC/I-2";

	*status = open_scanner(s);
	if (*status != SANE_STATUS_GOOD) {
		free(s);
		return NULL;
	}

	eds_dev_init(dev);

	/* lock scanner */
	*status = eds_lock(s);
	if (*status != SANE_STATUS_GOOD) {
		goto close;
	}

	/* discover capabilities */
	*status = esci2_info(s);
	if (*status != SANE_STATUS_GOOD)
		goto close;

	*status = esci2_capa(s);
	if (*status != SANE_STATUS_GOOD)
		goto close;

	*status = esci2_resa(s);
	if (*status != SANE_STATUS_GOOD)
		goto close;

	// assume 1 and 8 bit are always supported
	eds_add_depth(s->hw, 1);
	eds_add_depth(s->hw, 8);

	// setup area according to available options
	if (s->hw->has_fb) {

		dev->x_range = &dev->fbf_x_range;
		dev->y_range = &dev->fbf_y_range;
		dev->alignment = dev->fbf_alignment;

	} else if (s->hw->has_adf) {

		dev->x_range = &dev->adf_x_range;
		dev->y_range = &dev->adf_y_range;
		dev->alignment = dev->adf_alignment;

	} else {
		DBG(0, "unable to lay on the flatbed or feed the feeder. is that a scanner??\n");
	}

	*status = eds_dev_post_init(dev);
	if (*status != SANE_STATUS_GOOD)
		goto close;

	DBG(1, "scanner model: %s\n", dev->model);


	s->hw->lut_id = 0;

	for (int i = 0; i < stProfileMapArray.used; i++) {

		epsonds_profile_map* map = &stProfileMapArray.array[i];


		if (strcmp(map->productName, dev->model) == 0) {

			{//Convert to user friendly model name
				free(s->hw->model);

				s->hw->model = strdup(map->deviceID);
				s->hw->sane.model = s->hw->model;
			}
			{// set lutid
				s->hw->lut_id = map->lutID;
			}
			break;
		}
	}
	DBG(1, "scanner lut_id: %d\n", s->hw->lut_id);

	num_devices++;
	dev->next = first_dev;
	first_dev = dev;

	return s;

close:
	DBG(1, " failed\n");

	close_scanner(s);
	return NULL;
}


static SANE_Status
attach(const char *name, int type)
{
	SANE_Status status;
	epsonds_scanner * s;

	DBG(7, "%s: devname = %s, type = %d\n", __func__, name, type);

	s = device_detect(name, type, &status);
	if (s == NULL)
		return status;

	close_scanner(s);
	return status;
}

SANE_Status
attach_one_usb(const char *dev)
{
	DBG(7, "%s: dev = %s\n", __func__, dev);
	return attach(dev, SANE_EPSONDS_USB);
}

static SANE_Status
attach_one_net(const char *dev)
{
	char name[39 + 4];

	DBG(7, "%s: dev = %s\n", __func__, dev);

	strcpy(name, "net:");
	strcat(name, dev);
	return attach(name, SANE_EPSONDS_NET);
}

static void found_net_device(const char* device_name, const char* ip)
{
	DBG(7, "Found %s: ip = %s\n", device_name, ip);

	int foundSupportedDevice = 0;

	// search models
	for (int i = 0; i < stProfileMapArray.used; i++) {
		if (strcmp(stProfileMapArray.array[i].deviceID, device_name) == 0) {
			foundSupportedDevice = 1;
			break;
		}
	}


	if (foundSupportedDevice)
	{
		char name[39 + 4];

		strcpy(name, "net:");
		strncat(name, ip, 39);

		int foundCache = 0;
		// search cache and prents duplicated model
		for (epsonds_device* dev = first_dev; dev; dev = dev->next) {
			if (strcmp(dev->sane.name, name) == 0) {
				foundCache = 1;
			}
		}
		if (foundCache == 0)
		{
			attach(name, SANE_EPSONDS_NET);
		}
	}
}

static void
splitProfileName(const char* input, int* outProductID, char *outProductName, char* outDeviceID, int* outLutID)
{
    char target[1024];
    strncpy(target, input, 1023);

    strtok(target, ":");//profile

    //productID
    char* pid = strtok(NULL, ",");
    sscanf(pid, "%x", (unsigned int*)outProductID);

    //productName
    char* productName = strtok(NULL, ",");
    strncpy(outProductName, productName,  49);

    //deviceID
    char* deviceID = strtok(NULL, ",");
    strncpy(outDeviceID, deviceID,  49);

    //lutID
    char* lutID = strtok(NULL, ",");
    sscanf(lutID, "%d", outLutID);
}


static SANE_Status
attach_one_config(SANEI_Config __sane_unused__ *config, const char *line,
		  void *data)
{
	int vendor, product;
	SANE_Bool local_only = *(SANE_Bool*) data;
	int len = strlen(line);

	DBG(7, "%s: len = %d, line = %s\n", __func__, len, line);
	if (strncmp(line, "profile", 7) == 0 ) {
		DBG(7, " found profile device profile\n");

		epsonds_profile_map profle_map;

		splitProfileName(line, &profle_map.productID, profle_map.productName, profle_map.deviceID, &profle_map.lutID);

		DBG(7, "Found profile : %x %s %s %d\n", profle_map.productID, profle_map.productName, profle_map.deviceID, profle_map.lutID);

		insert_profile_map(&stProfileMapArray, profle_map);
	}else if (sscanf(line, "usb %i %i", &vendor, &product) == 2) {

		DBG(7, " user configured device\n");

		if (vendor != SANE_EPSONDS_VENDOR_ID)
			return SANE_STATUS_INVAL; /* this is not an Epson device */

		sanei_usb_attach_matching_devices(line, attach_one_usb);

	} else if (strncmp(line, "usb", 3) == 0 && len == 3) {

		DBG(7, " probing usb devices\n");

		for (int i = 0; i < stProfileMapArray.used; i++) {
			int usbPid = stProfileMapArray.array[i].productID;
			sanei_usb_find_devices(SANE_EPSONDS_VENDOR_ID, usbPid, attach_one_usb);
		}

	} else if (strncmp(line, "net", 3) == 0) {

		if (!local_only) {
			/* remove the "net" sub string */
			const char *name =
				sanei_config_skip_whitespace(line + 3);

			if (strncmp(name, "autodiscovery", 13) == 0)
			{
				#if WITH_AVAHI
				epsonds_searchDevices(found_net_device);
				#else
				// currently does not support
				//e2_network_discovery();
				#endif
			}
			else
				attach_one_net(name);
		}
	} else {
		DBG(0, "unable to parse config line: %s\n", line);
	}

	return SANE_STATUS_GOOD;
}

static void
free_devices(void)
{
	epsonds_device *dev, *next;

	for (dev = first_dev; dev; dev = next) {
		next = dev->next;
		free(dev->name);
		free(dev->model);
		free(dev);
	}

	free(devlist);
	first_dev = NULL;
}

static void
probe_devices(SANE_Bool local_only)
{
	DBG(5, "%s\n", __func__);

	free_devices();
	sanei_configure_attach(EPSONDS_CONFIG_FILE, NULL,
			       attach_one_config, &local_only);
}

/**** SANE API ****/

SANE_Status
sane_init(SANE_Int *version_code, SANE_Auth_Callback __sane_unused__ authorize)
{
	DBG_INIT();

	init_profile_maps(&stProfileMapArray, 100);

	DBG(2, "%s: " PACKAGE " " VERSION "\n", __func__);

	DBG(1, "epsonds backend, version %i.%i.%i\n",
		EPSONDS_VERSION, EPSONDS_REVISION, EPSONDS_BUILD);

	if (version_code != NULL)
		*version_code = SANE_VERSION_CODE(SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR,
					  EPSONDS_BUILD);

	sanei_usb_init();

	return SANE_STATUS_GOOD;
}

void
sane_exit(void)
{
	DBG(5, "** %s\n", __func__);
	free_profile_maps(&stProfileMapArray);
	free_devices();
}

SANE_Status
sane_get_devices(const SANE_Device ***device_list, SANE_Bool local_only)
{
	int i;
	epsonds_device *dev;

	DBG(5, "** %s  local_only = %d \n", __func__, local_only);


	probe_devices(local_only);

	devlist = malloc((num_devices + 1) * sizeof(devlist[0]));
	if (!devlist) {
		DBG(1, "out of memory (line %d)\n", __LINE__);
		return SANE_STATUS_NO_MEM;
	}

	DBG(5, "%s - results:\n", __func__);

	for (i = 0, dev = first_dev; i < num_devices && dev; dev = dev->next, i++) {
		DBG(1, " %d (%d): %s\n", i, dev->connection, dev->model);
		devlist[i] = &dev->sane;
	}

	devlist[i] = NULL;

	*device_list = devlist;


	return SANE_STATUS_GOOD;
}

static SANE_Status
init_options(epsonds_scanner *s)
{
	DBG(5, "init_options\n");
	int i;

	for (i = 0; i < NUM_OPTIONS; i++) {
		s->opt[i].size = sizeof(SANE_Word);
		s->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
	}

	s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
	s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
	s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT;
	s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
	s->val[OPT_NUM_OPTS].w = NUM_OPTIONS;

	/* "Scan Mode" group: */
	s->opt[OPT_STANDARD_GROUP].name = SANE_NAME_STANDARD;
	s->opt[OPT_STANDARD_GROUP].title = SANE_TITLE_STANDARD;
	s->opt[OPT_STANDARD_GROUP].desc = SANE_DESC_STANDARD;
	s->opt[OPT_STANDARD_GROUP].type = SANE_TYPE_GROUP;
	s->opt[OPT_STANDARD_GROUP].cap = 0;

	/* scan mode */
	s->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE;
	s->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
	s->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
	s->opt[OPT_MODE].type = SANE_TYPE_STRING;
	s->opt[OPT_MODE].size = max_string_size(mode_list);
	s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
	s->opt[OPT_MODE].constraint.string_list = mode_list;
	s->val[OPT_MODE].w = 0;	/* Lineart */

	/* bit depth */
	s->opt[OPT_DEPTH].name = SANE_NAME_BIT_DEPTH;
	s->opt[OPT_DEPTH].title = SANE_TITLE_BIT_DEPTH;
	s->opt[OPT_DEPTH].desc = SANE_DESC_BIT_DEPTH;
	s->opt[OPT_DEPTH].type = SANE_TYPE_INT;
	s->opt[OPT_DEPTH].unit = SANE_UNIT_BIT;
	s->opt[OPT_DEPTH].constraint_type = SANE_CONSTRAINT_WORD_LIST;
	s->opt[OPT_DEPTH].constraint.word_list = s->hw->depth_list;
	s->val[OPT_DEPTH].w = s->hw->depth_list[1];	/* the first "real" element is the default */

	/* default is Lineart, disable depth selection */
	s->opt[OPT_DEPTH].cap |= SANE_CAP_INACTIVE;

	/* resolution */
	s->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
	s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
	s->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;

	s->opt[OPT_RESOLUTION].type = SANE_TYPE_INT;
	s->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI;

	/* range */
	if (s->hw->dpi_range.quant) {
		s->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_RANGE;
		s->opt[OPT_RESOLUTION].constraint.range = &s->hw->dpi_range;
		s->val[OPT_RESOLUTION].w = s->hw->dpi_range.min;
	} else { /* list */
		s->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST;
		s->opt[OPT_RESOLUTION].constraint.word_list = s->hw->res_list;
		s->val[OPT_RESOLUTION].w = s->hw->res_list[1];
	}

	/* "Geometry" group: */
	s->opt[OPT_GEOMETRY_GROUP].title = SANE_I18N("Geometry");
	s->opt[OPT_GEOMETRY_GROUP].desc = "";
	s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
	s->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED;

	/* top-left x */
	s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
	s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
	s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
	s->opt[OPT_TL_X].type = SANE_TYPE_FIXED;
	s->opt[OPT_TL_X].unit = SANE_UNIT_MM;
	s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
	s->opt[OPT_TL_X].constraint.range = s->hw->x_range;
	s->val[OPT_TL_X].w = 0;

	/* top-left y */
	s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
	s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
	s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;

	s->opt[OPT_TL_Y].type = SANE_TYPE_FIXED;
	s->opt[OPT_TL_Y].unit = SANE_UNIT_MM;
	s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
	s->opt[OPT_TL_Y].constraint.range = s->hw->y_range;
	s->val[OPT_TL_Y].w = 0;

	/* bottom-right x */
	s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
	s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
	s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;

	s->opt[OPT_BR_X].type = SANE_TYPE_FIXED;
	s->opt[OPT_BR_X].unit = SANE_UNIT_MM;
	s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
	s->opt[OPT_BR_X].constraint.range = s->hw->x_range;
	s->val[OPT_BR_X].w = s->hw->x_range->max;

	/* bottom-right y */
	s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
	s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
	s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;

	s->opt[OPT_BR_Y].type = SANE_TYPE_FIXED;
	s->opt[OPT_BR_Y].unit = SANE_UNIT_MM;
	s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
	s->opt[OPT_BR_Y].constraint.range = s->hw->y_range;
	s->val[OPT_BR_Y].w = s->hw->y_range->max;

	/* "Optional equipment" group: */
	s->opt[OPT_EQU_GROUP].title = SANE_I18N("Optional equipment");
	s->opt[OPT_EQU_GROUP].desc = "";
	s->opt[OPT_EQU_GROUP].type = SANE_TYPE_GROUP;
	s->opt[OPT_EQU_GROUP].cap = SANE_CAP_ADVANCED;

	/* source */
	s->opt[OPT_SOURCE].name = SANE_NAME_SCAN_SOURCE;
	s->opt[OPT_SOURCE].title = SANE_TITLE_SCAN_SOURCE;
	s->opt[OPT_SOURCE].desc = SANE_DESC_SCAN_SOURCE;
	s->opt[OPT_SOURCE].type = SANE_TYPE_STRING;
	s->opt[OPT_SOURCE].size = max_string_size(source_list);
	s->opt[OPT_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
	s->opt[OPT_SOURCE].constraint.string_list = source_list;
	s->val[OPT_SOURCE].w = 0;

	s->opt[OPT_EJECT].name = "eject";
	s->opt[OPT_EJECT].title = SANE_I18N("Eject");
	s->opt[OPT_EJECT].desc = SANE_I18N("Eject the sheet in the ADF");
	s->opt[OPT_EJECT].type = SANE_TYPE_BUTTON;

	if (!s->hw->adf_has_eject)
		s->opt[OPT_EJECT].cap |= SANE_CAP_INACTIVE;

	s->opt[OPT_LOAD].name = "load";
	s->opt[OPT_LOAD].title = SANE_I18N("Load");
	s->opt[OPT_LOAD].desc = SANE_I18N("Load a sheet in the ADF");
	s->opt[OPT_LOAD].type = SANE_TYPE_BUTTON;

	if (!s->hw->adf_has_load)
		s->opt[OPT_LOAD].cap |= SANE_CAP_INACTIVE;


	s->opt[OPT_ADF_SKEW].name = "adf-skew";
	s->opt[OPT_ADF_SKEW].title = SANE_I18N("ADF Skew Correction");
	s->opt[OPT_ADF_SKEW].desc =
		SANE_I18N("Enables ADF skew correction");
	s->opt[OPT_ADF_SKEW].type = SANE_TYPE_BOOL;
	s->val[OPT_ADF_SKEW].w = 0;


	s->opt[OPT_ADF_CRP].name = "adf-crp";
	s->opt[OPT_ADF_CRP].title = SANE_I18N("ADF CRP Correction");
	s->opt[OPT_ADF_CRP].desc =
		SANE_I18N("Enables ADF auto cropping"); //
	s->opt[OPT_ADF_CRP].type = SANE_TYPE_BOOL;
	s->val[OPT_ADF_CRP].w = 0;


	if (!s->hw->adf_has_skew)
	{
		s->val[OPT_ADF_SKEW].w = 0;
		s->opt[OPT_ADF_SKEW].cap |= SANE_CAP_INACTIVE;
	}

	if(!s->hw->adf_has_crp)
	{
		s->val[OPT_ADF_CRP].w = 0;
		s->opt[OPT_ADF_CRP].cap |= SANE_CAP_INACTIVE;
	}

	return SANE_STATUS_GOOD;
}

SANE_Status
sane_open(SANE_String_Const name, SANE_Handle *handle)
{
	SANE_Status status;
	epsonds_scanner *s = NULL;



	DBG(7, "** %s: name = '%s'\n", __func__, name);

	/* probe if empty device name provided */
	if (name[0] == '\0') {

		probe_devices(SANE_FALSE);

		if (first_dev == NULL) {
			DBG(1, "no devices detected\n");
			return SANE_STATUS_INVAL;
		}

		s = device_detect(first_dev->sane.name, first_dev->connection,
					&status);
		if (s == NULL) {
			DBG(1, "cannot open a perfectly valid device (%s),"
				" please report to the authors\n", name);
			return SANE_STATUS_INVAL;
		}

	} else {

		if (strncmp(name, "net:", 4) == 0) {
			s = device_detect(name, SANE_EPSONDS_NET, &status);
			if (s == NULL)
				return status;
		} else if (strncmp(name, "libusb:", 7) == 0) {
			s = device_detect(name, SANE_EPSONDS_USB, &status);
			if (s == NULL)
				return status;
		} else {
			DBG(1, "invalid device name: %s\n", name);
			return SANE_STATUS_INVAL;
		}
	}

	/* s is always valid here */

	DBG(5, "%s: handle obtained\n", __func__);

	init_options(s);

	*handle = (SANE_Handle)s;

	status = open_scanner(s);
	if (status != SANE_STATUS_GOOD) {
		free(s);
		return status;
	}

	/* lock scanner if required */
	if (!s->locked) {
		status = eds_lock(s);
	}

	setvalue((SANE_Handle)s, OPT_MODE, (void*)SANE_VALUE_SCAN_MODE_COLOR, NULL);

	return status;
}

void
sane_close(SANE_Handle handle)
{
	epsonds_scanner *s = (epsonds_scanner *)handle;

	DBG(1, "** %s\n", __func__);

	close_scanner(s);
}

const SANE_Option_Descriptor *
sane_get_option_descriptor(SANE_Handle handle, SANE_Int option)
{
	epsonds_scanner *s = (epsonds_scanner *) handle;

	if (option < 0 || option >= NUM_OPTIONS)
		return NULL;

	return s->opt + option;
}

static const SANE_String_Const *
search_string_list(const SANE_String_Const *list, SANE_String value)
{
	while (*list != NULL && strcmp(value, *list) != 0)
		list++;

	return ((*list == NULL) ? NULL : list);
}

/*
 * Handles setting the source (flatbed, transparency adapter (TPU),
 * or auto document feeder (ADF)).
 *
 * For newer scanners it also sets the focus according to the
 * glass / TPU settings.
 */

static void
change_source(epsonds_scanner *s, SANE_Int optindex, char *value)
{
	int force_max = SANE_FALSE;

	DBG(1, "%s: optindex = %d, source = '%s'\n", __func__, optindex,
	    value);

	s->val[OPT_SOURCE].w = optindex;

	/* if current selected area is the maximum available,
	 * keep this setting on the new source.
	 */
	if (s->val[OPT_TL_X].w == s->hw->x_range->min
	    && s->val[OPT_TL_Y].w == s->hw->y_range->min
	    && s->val[OPT_BR_X].w == s->hw->x_range->max
	    && s->val[OPT_BR_Y].w == s->hw->y_range->max) {
		force_max = SANE_TRUE;
	}

	if (strcmp(STRING_ADFFRONT, value) == 0 || strcmp(STRING_ADFDUPLEX, value) == 0) {
		s->hw->x_range = &s->hw->adf_x_range;
		s->hw->y_range = &s->hw->adf_y_range;
		s->hw->alignment = s->hw->adf_alignment;


	} else if (strcmp(TPU_STR, value) == 0) {

		s->hw->x_range = &s->hw->tpu_x_range;
		s->hw->y_range = &s->hw->tpu_y_range;

	} else {

		/* neither ADF nor TPU active, assume FB */
		s->hw->x_range = &s->hw->fbf_x_range;
		s->hw->y_range = &s->hw->fbf_y_range;
		s->hw->alignment = s->hw->fbf_alignment;
	}

	s->opt[OPT_BR_X].constraint.range = s->hw->x_range;
	s->opt[OPT_BR_Y].constraint.range = s->hw->y_range;

	if (s->val[OPT_TL_X].w < s->hw->x_range->min || force_max)
		s->val[OPT_TL_X].w = s->hw->x_range->min;

	if (s->val[OPT_TL_Y].w < s->hw->y_range->min || force_max)
		s->val[OPT_TL_Y].w = s->hw->y_range->min;

	if (s->val[OPT_BR_X].w > s->hw->x_range->max || force_max)
		s->val[OPT_BR_X].w = s->hw->x_range->max;

	if (s->val[OPT_BR_Y].w > s->hw->y_range->max || force_max)
		s->val[OPT_BR_Y].w = s->hw->y_range->max;
}

static SANE_Status
getvalue(SANE_Handle handle, SANE_Int option, void *value)
{
	epsonds_scanner *s = (epsonds_scanner *)handle;
	SANE_Option_Descriptor *sopt = &(s->opt[option]);
	Option_Value *sval = &(s->val[option]);

	DBG(17, "%s: option = %d\n", __func__, option);

	switch (option) {

	case OPT_NUM_OPTS:
	case OPT_RESOLUTION:
	case OPT_TL_X:
	case OPT_TL_Y:
	case OPT_BR_X:
	case OPT_BR_Y:
	case OPT_DEPTH:
	case OPT_ADF_SKEW:
		*((SANE_Word *) value) = sval->w;
		break;

	case OPT_MODE:
	case OPT_SOURCE:
		strcpy((char *) value, sopt->constraint.string_list[sval->w]);
		break;

	default:
		return SANE_STATUS_INVAL;
	}

	return SANE_STATUS_GOOD;
}

static SANE_Status
setvalue(SANE_Handle handle, SANE_Int option, void *value, SANE_Int *info)
{
	epsonds_scanner *s = (epsonds_scanner *) handle;
	SANE_Option_Descriptor *sopt = &(s->opt[option]);
	Option_Value *sval = &(s->val[option]);

	SANE_Status status;
	const SANE_String_Const *optval = NULL;
	int optindex = 0;
	SANE_Bool reload = SANE_FALSE;

	DBG(17, "** %s: option = %d, value = %p\n", __func__, option, value);

	status = sanei_constrain_value(sopt, value, info);
	if (status != SANE_STATUS_GOOD)
		return status;

	if (info && value && (*info & SANE_INFO_INEXACT)
	    && sopt->type == SANE_TYPE_INT)
		DBG(17, " constrained val = %d\n", *(SANE_Word *) value);

	if (sopt->constraint_type == SANE_CONSTRAINT_STRING_LIST) {
		optval = search_string_list(sopt->constraint.string_list,
					    (char *) value);
		if (optval == NULL)
			return SANE_STATUS_INVAL;
		optindex = optval - sopt->constraint.string_list;
	}

	/* block faulty frontends */
	if (sopt->cap & SANE_CAP_INACTIVE) {
		DBG(1, " tried to modify a disabled parameter");
		return SANE_STATUS_INVAL;
	}

	switch (option) {

	case OPT_ADF_SKEW:
	case OPT_RESOLUTION:
	case OPT_ADF_CRP:
		sval->w = *((SANE_Word *) value);
		reload = SANE_TRUE;
		break;

	case OPT_BR_X:
	case OPT_BR_Y:
		if (SANE_UNFIX(*((SANE_Word *) value)) == 0) {
			DBG(17, " invalid br-x or br-y\n");
			return SANE_STATUS_INVAL;
		}
		// fall through
	case OPT_TL_X:
	case OPT_TL_Y:

		sval->w = *((SANE_Word *) value);
		if (NULL != info)
			*info |= SANE_INFO_RELOAD_PARAMS;

		if (option == OPT_BR_X)
		{
			DBG(17, "OPT_BR_X = %d\n", sval->w);
		}
		if (option == OPT_BR_Y)
		{
			DBG(17, "OPT_BR_Y = %d\n", sval->w);
		}
		if (option == OPT_TL_X)
		{
			DBG(17, "OPT_TL_X = %d\n", sval->w);
		}
		if (option == OPT_TL_Y)
		{
			DBG(17, "OPT_TL_Y = %d\n", sval->w);
		}
		// adf crop set to off
		s->val[OPT_ADF_CRP].w = 0;
		break;

	case OPT_SOURCE:
		change_source(s, optindex, (char *) value);
		reload = SANE_TRUE;
		break;

	case OPT_MODE:
	{
		DBG(17, " OPT_MODE = index %d\n", optindex);

		/* use JPEG mode if RAW is not available when bpp > 1 */
		if (optindex > 0 && !s->hw->has_raw) {
			s->mode_jpeg = 1;
		} else {
			s->mode_jpeg = 0;
		}

		sval->w = optindex;

		/* if binary, then disable the bit depth selection */
		if (optindex == 0) {
			s->opt[OPT_DEPTH].cap |= SANE_CAP_INACTIVE;
		} else {
			if (s->hw->depth_list[0] == 1)
				s->opt[OPT_DEPTH].cap |= SANE_CAP_INACTIVE;
			else {
				s->opt[OPT_DEPTH].cap &= ~SANE_CAP_INACTIVE;
				s->val[OPT_DEPTH].w =
					mode_params[optindex].depth;
			}
		}

		reload = SANE_TRUE;
		break;
	}

	case OPT_DEPTH:
		sval->w = *((SANE_Word *) value);
		mode_params[s->val[OPT_MODE].w].depth = sval->w;
		reload = SANE_TRUE;
		break;

	case OPT_LOAD:
		esci2_mech(s, "#ADFLOAD");
		break;

	case OPT_EJECT:
		esci2_mech(s, "#ADFEJCT");
		break;

	default:
		return SANE_STATUS_INVAL;
	}

	if (reload && info != NULL)
		*info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;

	return SANE_STATUS_GOOD;
}

SANE_Status
sane_control_option(SANE_Handle handle, SANE_Int option, SANE_Action action,
		    void *value, SANE_Int *info)
{
	DBG(17, "** %s: action = %x, option = %d\n", __func__, action, option);

	if (option < 0 || option >= NUM_OPTIONS)
		return SANE_STATUS_INVAL;

	if (info != NULL)
		*info = 0;

	switch (action) {
	case SANE_ACTION_GET_VALUE:
		return getvalue(handle, option, value);

	case SANE_ACTION_SET_VALUE:
		return setvalue(handle, option, value, info);

	default:
		return SANE_STATUS_INVAL;
	}

	return SANE_STATUS_INVAL;
}


static void setBit (SANE_Byte* bytes, SANE_Int bitIndex, SANE_Bool isTrue)
{
    SANE_Int octet = bitIndex / 8;
    SANE_Byte  bit   = 7 - (bitIndex % 8);

    if (isTrue) {
        bytes[octet] |=  (1 << bit);
    } else {
        bytes[octet] &= ~(1 << bit);
    }
}

static SANE_Bool getBit (SANE_Byte* bytes, SANE_Int bitIndex)
{
    SANE_Int octet = bitIndex / 8;
    SANE_Byte mask = 1 << (7 - (bitIndex % 8));

    if( bytes[octet] & mask ){
        return SANE_TRUE;
    }

    return SANE_FALSE;
}

static void swapPixel1(SANE_Int  x1,
                       SANE_Int  y1,
                       SANE_Int  x2,
                       SANE_Int  y2,
                       SANE_Byte*  bytes,
                       SANE_Byte   bitsPerSample,
                       SANE_Int  samplesPerPixel,
                       SANE_Int  bytesPerRow)
{
    SANE_Int pixelBits =  bitsPerSample * samplesPerPixel;
    SANE_Int widthBits =  bytesPerRow * 8;

    SANE_Byte temp = getBit(bytes, widthBits * y1 + x1 * pixelBits);
    {
        SANE_Byte right =  getBit(bytes, widthBits * y2 + x2 * pixelBits);
        setBit(bytes, widthBits * y1 + x1 * pixelBits, right);
    }
    setBit(bytes, widthBits * y2 + x2 * pixelBits, temp);
}

static void swapPixel8(SANE_Int  x1,
                       SANE_Int  y1,
                       SANE_Int  x2,
                       SANE_Int  y2,
                       SANE_Byte*  bytes,
                       SANE_Byte   bitsPerSample,
                       SANE_Int  samplesPerPixel,
                       SANE_Int  bytesPerRow)
{
    SANE_Int pixelBytes =  samplesPerPixel * bitsPerSample / 8;

    for (SANE_Byte i = 0; i < pixelBytes; i++) {
        SANE_Byte temp = bytes[y1 * bytesPerRow +  (pixelBytes *  x1 + i)];
        bytes[y1 * bytesPerRow + (pixelBytes * x1 + i)] =  bytes[y2 * bytesPerRow +  (pixelBytes * x2 + i)];
        bytes[y2 * bytesPerRow + (pixelBytes * x2 + i)] =  temp;
    }
}



static void swapPixel(SANE_Int  x1,
                      SANE_Int  y1,
                      SANE_Int  x2,
                      SANE_Int  y2,
                      SANE_Byte*  bytes,
                      SANE_Byte   bitsPerSample,
                      SANE_Int  samplesPerPixel,
                      SANE_Int  bytesPerRow)
{
    if (bitsPerSample == 1) {
        swapPixel1(x1, y1, x2, y2, bytes, bitsPerSample, samplesPerPixel, bytesPerRow);
    }else if(bitsPerSample == 8 || bitsPerSample == 16){
        swapPixel8(x1, y1, x2, y2, bytes, bitsPerSample, samplesPerPixel, bytesPerRow);
    }
}


void
upside_down_backside_image(epsonds_scanner *s)
{
	// get all data from ring_buffer
	if (eds_ring_avail(&s->back)  &&
	    (strcmp(s->hw->sane.model, (char*)"DS-1630") == 0
		 || strcmp(s->hw->sane.model, (char*)"DS-1610") == 0
		 || strcmp(s->hw->sane.model, (char*)"DS-1660W") == 0))
	{
		SANE_Int bytesPerLine = s->params.bytes_per_line;
		SANE_Int imageSize = bytesPerLine * s->height_back;

		SANE_Byte* workBuffer = malloc(imageSize);
		// if there is not enough memory, do nothing.
		if (workBuffer)
		{
			eds_ring_read(&s->back, workBuffer, imageSize);
			SANE_Int  samplesPerPxel = 3;
			if (s->params.format == SANE_FRAME_RGB)
			{
				samplesPerPxel = 3;
			}
			else if (s->params.format == SANE_FRAME_GRAY)
			{
				samplesPerPxel = 1;
			}

			SANE_Int half = (s->height_back / 2) - 1;
			if (half < 0) {
				half = 0;
			}

			if((s->height_back % 2) == 1) {
				SANE_Int ymid = ( (s->height_back - 1 ) / 2 );
				for(SANE_Int x = 0;x < (s->width_back / 2); x++) {
					swapPixel(x, ymid, s->width_back - x - 1, ymid, workBuffer, s->params.depth, samplesPerPxel, s->params.bytes_per_line);
				}
			}

			if (s->height_back != 1) {
				for(SANE_Int x = 0; x < s->width_back; x++) {
					for(SANE_Int y = 0;y <= half; y++) {
						swapPixel(x, y, s->width_back - x - 1, s->height_back - y -1, workBuffer, s->params.depth, samplesPerPxel, s->params.bytes_per_line);
					}
				}
			}

			eds_ring_write(&s->back, workBuffer, imageSize);
			free(workBuffer);
			workBuffer = NULL;

		}
	}

}


SANE_Status
get_next_image(epsonds_scanner *s)
{
	SANE_Status status = SANE_STATUS_GOOD;

	if (s->acquirePage == 0 && s->current == &s->front)
	{
		DBG(20, "** %s:  get_next_image\n", __func__);


		/*page info will be updatted by pen*/
		s->width_back = 0;
		s->width_front = 0;
		s->height_back = 0;
		s->height_front = 0;

		if (s->mode_jpeg)
		{
			status = acquire_and_decode_jpeg_data(s);
		}else{
			status = acquire_raw_data(s);
		}
		if (status != SANE_STATUS_GOOD)
		{
			eds_ring_flush(&s->front);
			eds_ring_flush(&s->back);
			eds_ring_destory(&s->front);
			eds_ring_destory(&s->back);
		}
		DBG(20," ringFront = %d ringBack = %d\n", eds_ring_avail(&s->front), eds_ring_avail(&s->back));

		s->acquirePage = 1;
	}

	return status;
}


SANE_Status
sane_get_parameters(SANE_Handle handle, SANE_Parameters *params)
{
	epsonds_scanner *s = (epsonds_scanner *)handle;

	DBG(5, "** %s\n", __func__);

	if (params == NULL)
		DBG(1, "%s: params is NULL\n", __func__);

	/*
	 * If sane_start was already called, then just retrieve the parameters
	 * from the scanner data structure
	 */
	if (s->scanning) {
		DBG(5, "scan in progress, returning saved params structure\n");
	} else {
		/* otherwise initialize the params structure */
		eds_init_parameters(s);
	}


	SANE_Status status = SANE_STATUS_GOOD;

	status = get_next_image(s);

	// if size auto, update page size value
	if(s->val[OPT_ADF_CRP].w)
	{
		// frontside
		if (s->current == &s->front)
		{
			DBG(20, "front side \n");
			if (s->width_front != 0 && s->height_front != 0)
			{
				if (s->params.format == SANE_FRAME_RGB)
				{
					s->params.bytes_per_line = s->width_front * 3;
					s->params.pixels_per_line = s->width_front;
				}

				if (s->params.format == SANE_FRAME_GRAY && s->params.depth == 8)
				{
					s->params.bytes_per_line = s->width_front;
					s->params.pixels_per_line = s->width_front;
				}

				if (s->params.format == SANE_FRAME_GRAY && s->params.depth == 1)
				{
					s->params.bytes_per_line = (s->width_front + 7)/8;
					s->params.pixels_per_line = s->width_front;
				}
				s->params.lines = s->height_front;
			}
		}
		// backside
		if (s->current == &s->back)
		{
			DBG(20, "back side \n");
			if (s->width_back != 0 && s->height_back != 0)
			{
				if (s->params.format == SANE_FRAME_RGB)
				{
					s->params.bytes_per_line = s->width_back * 3;
					s->params.pixels_per_line = s->width_back;
				}

				if (s->params.format == SANE_FRAME_GRAY && s->params.depth == 8)
				{
					s->params.bytes_per_line = s->width_back;
					s->params.pixels_per_line = s->width_back;
				}

				if (s->params.format == SANE_FRAME_GRAY && s->params.depth == 1)
				{
					s->params.bytes_per_line = (s->width_back + 7)/8;
					s->params.pixels_per_line = s->width_back;
				}
				s->params.lines = s->height_back;
			}
		}
	}
	if (params != NULL)
		*params = s->params;

	print_params(s->params);

	DBG(20, "s->params.line  = %d  s->params.bytes_per_line = %d s->params.pixels_per_line = %d \n", s->params.lines, s->params.bytes_per_line , s->params.pixels_per_line );
	return status;
}



typedef float ColorMatrix[3][3];

#define CCT_TABLE_SIZE 9
static int get_roundup_index(double frac[], int n)
{
    int        i, index = -1;
    double    max_val = 0.0;

    for (i=0; i<n; i++) {
        if (frac[i]<0) continue;
        if (max_val<frac[i]) {
            index = i;
            max_val = frac[i];
        }
    }
    return index;
}

static int get_rounddown_index(double frac[], int n)
{
    int        i, index = -1;
    double    min_val  = 1.0;

    for (i=0; i<n; i++) {
        if (frac[i]>0) continue;
        if (min_val>frac[i]) {
            index = i;
            min_val = frac[i];
        }
    }
    return index;
}


void ESCIRoundColorCorrectionMatrix(int mult, double org_cct[], int rnd_cct[])
{
    int        i, j, index;
    double    mult_cct[CCT_TABLE_SIZE], frac[CCT_TABLE_SIZE];
    int        sum[3];
    int        loop;

    for (i=0; i<CCT_TABLE_SIZE; i++) {
        mult_cct[i] = org_cct[i] * mult;
    }

    // round value multiplied by 'mult' off to integer.
    for (i=0; i<CCT_TABLE_SIZE; i++) {
        rnd_cct[i] = (int)floor(org_cct[i] * mult + 0.5);
    }

    loop=0;
    do {
        // If all element equal to 11, diagonal element is set to 10.
        for (i=0; i<3; i++) {
            if (    (rnd_cct[i*3]==11) &&
                (rnd_cct[i*3]==rnd_cct[i*3+1]) &&
                (rnd_cct[i*3]==rnd_cct[i*3+2])    ) {
                rnd_cct[i*3+i] --;
                mult_cct[i*3+i] = rnd_cct[i*3+i];
            }
        }
        // calc. summation of each line.
        for (i=0; i<3; i++) {
            sum[i] = 0;
            for (j=0; j<3; j++) {
                sum[i] += rnd_cct[i*3+j];
            }
        }
        // calc. values rounded up or down.
        for (i=0; i<CCT_TABLE_SIZE; i++) {
            frac[i] = mult_cct[i] - rnd_cct[i];
        }

        // if summation does not equal to 'mult', adjust rounded up or down value.
        for (i=0; i<3; i++) {
            if (sum[i]<mult) {
                index = get_roundup_index(&frac[i*3], 3);
                if (index!=-1) {
                    rnd_cct[i*3+index] ++;
                    mult_cct[i*3+index] = rnd_cct[i*3+index];
                    sum[i]++;
                }
            } else if (sum[i]>mult) {
                index = get_rounddown_index(&frac[i*3], 3);
                if (index!=-1) {
                    rnd_cct[i*3+index] --;
                    mult_cct[i*3+index] = rnd_cct[i*3+index];
                    sum[i]--;
                }
            }
        }

    } while ((++loop<2)&&((sum[0]!=mult)||(sum[1]!=mult)||(sum[2]!=mult)));
}



/*
 * This function is part of the SANE API and gets called from the front end to
 * start the scan process.
 */
#define CMD_BUF_SIZE 1000
SANE_Status
sane_start(SANE_Handle handle)
{
	epsonds_scanner *s = (epsonds_scanner *)handle;
	char buf[65]; /* add one more byte to correct buffer overflow issue */
	char cmd[CMD_BUF_SIZE]; /* take care not to overflow */
	SANE_Status status = 0;

	s->pages++;

	DBG(5, "** %s, pages = %d, scanning = %d, backside = %d, front fill: %d, back fill: %d\n",
		__func__, s->pages, s->scanning, s->backside,
		eds_ring_avail(&s->front),
		eds_ring_avail(&s->back));

	s->eof = 0;
	s->canceling = 0;
	s->acquirePage = 0;

	if ((s->pages % 2) == 1) {
		s->current = &s->front;
	} else if (eds_ring_avail(&s->back)) {
		DBG(5, "back side\n");
		s->current = &s->back;
	}

	/* scan already in progress? (one pass adf) */
	if (s->scanning  || eds_ring_avail(&s->back) > 0) {
		DBG(5, " scan in progress, returning early\n");
		return get_next_image(s);
	}
	if (strcmp(source_list[s->val[OPT_SOURCE].w], STRING_ADFFRONT) == 0 || strcmp(source_list[s->val[OPT_SOURCE].w], STRING_ADFDUPLEX) == 0) {
		if (s->scanEnd)
		{
	  		 s->scanEnd = 0;
	  		 return SANE_STATUS_NO_DOCS;
		}
	}else{
	   s->scanEnd = 0;
	}

	/* calc scanning parameters */
	status = eds_init_parameters(s);
	if (status != SANE_STATUS_GOOD) {
		DBG(1, " parameters initialization failed\n");
		return status;
	}

	/* allocate line buffer */
	s->line_buffer = realloc(s->line_buffer, s->params.bytes_per_line);
	if (s->line_buffer == NULL)
		return SANE_STATUS_NO_MEM;

	/* transfer buffer size, bsz */
	/* XXX read value from scanner */
	s->bsz = (1048576 * 4);

	/* transfer buffer */
	s->buf = realloc(s->buf, s->bsz);
	if (s->buf == NULL)
		return SANE_STATUS_NO_MEM;

	print_params(s->params);

	/* set scanning parameters */

	s->isDuplexScan = 0;
	/* document source */
	if (strcmp(source_list[s->val[OPT_SOURCE].w], STRING_ADFFRONT) == 0 || strcmp(source_list[s->val[OPT_SOURCE].w], STRING_ADFDUPLEX) == 0) {

		SANE_Int status = esci2_stat(s);
		if (status == SANE_STATUS_NO_DOCS)
		{
		   return SANE_STATUS_NO_DOCS;
		}

		SANE_Int duplexMode = (strcmp(source_list[s->val[OPT_SOURCE].w], STRING_ADFDUPLEX) == 0);

		sprintf(buf, "#ADF%s%s%s",
		duplexMode ? "DPLX" : "",
		s->val[OPT_ADF_SKEW].w ? "SKEW" : "",
		s->val[OPT_ADF_CRP].w ? "CRP " : ""
		);

		if (duplexMode)
		{
			s->isDuplexScan = 1;
		}
		s->isflatbedScan = 0;
	}
	else if (strcmp(source_list[s->val[OPT_SOURCE].w], STRING_FLATBED) == 0) {

		strcpy(buf, "#FB ");
		s->isflatbedScan = 1;

	} else {
		/* XXX */
	}

	strcpy(cmd, buf);

	s->needToConvertBW = 0;

	if (s->params.format == SANE_FRAME_GRAY) {
		if (s->params.depth == 1 && s->hw->has_mono == 0)
		{
			sprintf(buf, "#COLM008");
			s->needToConvertBW = 1;
			s->mode_jpeg = 1;
		}else
		{
			sprintf(buf, "#COLM%03d", s->params.depth);
		}
	} else if (s->params.format == SANE_FRAME_RGB) {
		sprintf(buf, "#COLC%03d", s->params.depth * 3);
	}

	strcat(cmd, buf);

	/* image transfer format */
	if (!s->mode_jpeg) {
		if (s->params.depth > 1 || s->hw->has_raw) {
			strcat(cmd, "#FMTRAW ");
		}
	} else {
		strcat(cmd, "#FMTJPG #JPGd090");
	}

	/* set GMM */
	if (s->params.depth == 1)
	{
		sprintf(buf, "#GMMUG10");
	} else
	{
		sprintf(buf, "#GMMUG18");
	}
	strcat(cmd, buf);

	/* resolution (RSMi not always supported) */

	if (strcmp(source_list[s->val[OPT_SOURCE].w], STRING_ADFFRONT) == 0 && s->val[OPT_RESOLUTION].w > 600) {
		DBG(0, "Automatic Document Feeder supported resolution of 600dpi or less. \n");
	} else if (s->val[OPT_RESOLUTION].w > 999) {
		sprintf(buf, "#RSMi%07d#RSSi%07d", s->val[OPT_RESOLUTION].w, s->val[OPT_RESOLUTION].w);
	} else {
		sprintf(buf, "#RSMd%03d#RSSd%03d", s->val[OPT_RESOLUTION].w, s->val[OPT_RESOLUTION].w);
	}

		if (strcmp(source_list[s->val[OPT_SOURCE].w], STRING_ADFDUPLEX) == 0 && s->val[OPT_RESOLUTION].w > 600) {
		DBG(0, "Automatic Document Feeder supported resolution of 600dpi or less. \n");
	} else if (s->val[OPT_RESOLUTION].w > 999) {
		sprintf(buf, "#RSMi%07d#RSSi%07d", s->val[OPT_RESOLUTION].w, s->val[OPT_RESOLUTION].w);
	} else {
		sprintf(buf, "#RSMd%03d#RSSd%03d", s->val[OPT_RESOLUTION].w, s->val[OPT_RESOLUTION].w);
	}

	strcat(cmd, buf);

	if (strcmp(s->hw->sane.model, (char*)"DS-70") == 0 || strcmp(s->hw->sane.model, (char*)"ES-65WR") == 0 || strcmp(s->hw->sane.model, (char*)"ES-60W") == 0
	|| strcmp(s->hw->sane.model, (char*)"DS-80W") == 0 || strcmp(s->hw->sane.model, (char*)"ES-55R") == 0 || strcmp(s->hw->sane.model, (char*)"ES-50") == 0){
		sprintf(buf, "#BSZi0262144");
		strcat(cmd, buf);
	}
	else {
		sprintf(buf, "#BSZi1048576");
		strcat(cmd, buf);
	}


	/* scanning area */

	sprintf(buf, "#ACQi%07di%07di%07di%07d",
		s->left, s->top, s->params.pixels_per_line, s->params.lines);


	if (strcmp(source_list[s->val[OPT_SOURCE].w], STRING_ADFFRONT) == 0 || strcmp(source_list[s->val[OPT_SOURCE].w], STRING_ADFDUPLEX) == 0) {
		status = esci2_stat(s);
		if (status != SANE_STATUS_GOOD) {
			goto end;
		}
	}

	strcat(cmd, buf);


	int pos = 0;

	{
		for (int i = 0; i < CMD_BUF_SIZE; i++)
		{
			// find end of string
			if(cmd[i] == 0)
			{
				pos = i;
				break;
			}
		}


		if (s->params.format == SANE_FRAME_GRAY && s->params.depth == 8) {
			DBG(10, "SANE_FRAME_GRAY\n");
			cmd[pos++] = '#';
			cmd[pos++] = 'G';
			cmd[pos++] = 'M';
			cmd[pos++] = 'T';
			cmd[pos++] = 'M';
			cmd[pos++] = 'O';
			cmd[pos++] = 'N';
			cmd[pos++] = 'O';
			cmd[pos++] = 'h';
			cmd[pos++] = '1';
			cmd[pos++] = '0';
			cmd[pos++] = '0';

			for(int count = 0; count < 256; count++) {
				cmd[pos++] =  LUT[s->hw->lut_id][count];
			}
		}
		if (s->params.format == SANE_FRAME_GRAY && s->params.depth == 1) {
			DBG(10, "SANE_FRAME_GRAY\n");
			cmd[pos++] = '#';
			cmd[pos++] = 'G';
			cmd[pos++] = 'M';
			cmd[pos++] = 'T';
			cmd[pos++] = 'M';
			cmd[pos++] = 'O';
			cmd[pos++] = 'N';
			cmd[pos++] = 'O';
			cmd[pos++] = 'h';
			cmd[pos++] = '1';
			cmd[pos++] = '0';
			cmd[pos++] = '0';

			for(int count = 0; count < 256; count++) {
				cmd[pos++] =  LUT[0][count];
			}
		}
		else if (s->params.format == SANE_FRAME_RGB) {
			DBG(10, "SANE_FRAME_RGB\n");
			cmd[pos++] = '#';
			cmd[pos++] = 'G';
			cmd[pos++] = 'M';
			cmd[pos++] = 'T';
			cmd[pos++] = 'R';
			cmd[pos++] = 'E';
			cmd[pos++] = 'D';
			cmd[pos++] = ' ';
			cmd[pos++] = 'h';
			cmd[pos++] = '1';
			cmd[pos++] = '0';
			cmd[pos++] = '0';

			for(int count = 0; count < 256; count++) {
				cmd[pos++] =  LUT_R[s->hw->lut_id][count];
			}

			cmd[pos++] = '#';
			cmd[pos++] = 'G';
			cmd[pos++] = 'M';
			cmd[pos++] = 'T';
			cmd[pos++] = 'G';
			cmd[pos++] = 'R';
			cmd[pos++] = 'N';
			cmd[pos++] = ' ';
			cmd[pos++] = 'h';
			cmd[pos++] = '1';
			cmd[pos++] = '0';
			cmd[pos++] = '0';

			for(int count = 0; count < 256; count++) {
				cmd[pos++] =  LUT_G[s->hw->lut_id][count];
			}

			cmd[pos++] = '#';
			cmd[pos++] = 'G';
			cmd[pos++] = 'M';
			cmd[pos++] = 'T';
			cmd[pos++] = 'B';
			cmd[pos++] = 'L';
			cmd[pos++] = 'U';
			cmd[pos++] = ' ';
			cmd[pos++] = 'h';
			cmd[pos++] = '1';
			cmd[pos++] = '0';
			cmd[pos++] = '0';

			for(int count = 0; count < 256; count++) {
				cmd[pos++] =  LUT_B[s->hw->lut_id][count];
			}
		}
		cmd[pos] = 0;

	}
	{// Set Color Matrix
		if (s->params.format == SANE_FRAME_RGB && s->hw->lut_id != 0 )/*Color Matrix Target devide and color Scan*/
		{
			ColorMatrix matrix;

			// DS-530

			if (s->hw->lut_id == 2)
			{
				// R
				matrix[0][0] = 1.0229;
				matrix[0][1] = 0.0009;
				matrix[0][2] = -0.0238;

				// G
				matrix[1][0] = 0.0031;
				matrix[1][1] = 1.0287;
				matrix[1][2] = -0.0318;

				//B
				matrix[2][0] = 0.0044;
				matrix[2][1] = -0.1150;
				matrix[2][2] = 1.1106;
			}

			// DS-1660W Flatbed

			if (s->hw->lut_id == 4)
			{
				// R
				matrix[0][0] = 1.0229;
				matrix[0][1] = 0.0009;
				matrix[0][2] = -0.0238;

				// G
				matrix[1][0] = 0.0031;
				matrix[1][1] = 1.0287;
				matrix[1][2] = -0.0318;

				//B
				matrix[2][0] = 0.0044;
				matrix[2][1] = -0.1150;
				matrix[2][2] = 1.1106;
			}


			// DS-320

			if (s->hw->lut_id == 5)
			{
				// R
				matrix[0][0] = 1.0250;
				matrix[0][1] = 0.0004;
				matrix[0][2] = -0.0254;

				// G
				matrix[1][0] = 0.0003;
				matrix[1][1] = 1.0022;
				matrix[1][2] = -0.0025;

				//B
				matrix[2][0] = 0.0049;
				matrix[2][1] = -0.0949;
				matrix[2][2] = 1.0900;
			}


			// ES-50

			if (s->hw->lut_id == 6)
			{
				// R
				matrix[0][0] = 1.0383;
				matrix[0][1] = -0.0021;
				matrix[0][2] = -0.0362;

				// G
				matrix[1][0] = 0.0046;
				matrix[1][1] = 1.0576;
				matrix[1][2] = -0.0622;

				//B
				matrix[2][0] = 0.0235;
				matrix[2][1] = -0.2396;
				matrix[2][2] = 1.2161;
			}


			// R
			matrix[0][0] = 0.9864;
			matrix[0][1] = 0.0248;
			matrix[0][2] = -0.0112;

			// G
			matrix[1][0] = 0.0021;
			matrix[1][1] = 1.0100;
			matrix[1][2] = -0.0112;

			//B
			matrix[2][0] = 0.0139;
			matrix[2][1] = -0.1249;
			matrix[2][2] = 1.1110;


			// Set Matrix value
			{
				cmd[pos++] = '#';
				cmd[pos++] = 'C';
				cmd[pos++] = 'M';
				cmd[pos++] = 'X';
				cmd[pos++] = 'U';
				cmd[pos++] = 'M';
				cmd[pos++] = '0';
				cmd[pos++] = '8';
				cmd[pos++] = 'h';
				cmd[pos++] = '0';
				cmd[pos++] = '0';
				cmd[pos++] = '9';
			}


			// Matrix to be sent to scanner must be following d1-d9 order:
			//
			//     G  R  B
			// G [d1 d4 d7]
			// R [d2 d5 d8]
			// B [d3 d6 d9]
			//
			// So, we will convert it with index table.
			char index[9] = {4, 1, 7, 3, 0, 6, 5, 2, 8};

			double flatten[9] = {0};
			for (int row = 0; row < 3; row++) {
				for (int col = 0; col < 3; col++) {
					flatten[row * 3 + col] = matrix[row][col];
				}
			}

			int rounded[9] = {0};
			ESCIRoundColorCorrectionMatrix(32, flatten, rounded);


			char ordered[9] = {0};
			for (int row = 0; row < 3; row++) {
				for (int col = 0; col < 3; col++) {
					int val = rounded[row * 3 + col];
					unsigned char oct = (unsigned char)abs(val);
					oct |= ((val < 0) ? (1 << 7) : 0);
					ordered[(signed char)index[row * 3 + col]] = oct;
				}
			}
			{
				cmd[pos++] = ordered[0];
				cmd[pos++] = ordered[1];
				cmd[pos++] = ordered[2];
				cmd[pos++] = ordered[3];
				cmd[pos++] = ordered[4];
				cmd[pos++] = ordered[5];
				cmd[pos++] = ordered[6];
				cmd[pos++] = ordered[7];
				cmd[pos++] = ordered[8];
				cmd[pos++] = 0; //padding
 				cmd[pos++] = 0; //padding
				cmd[pos++] = 0; //padding


				DBG(1, "color matrix\n");
				for (int i = 0; i < 9; i++)
				{
					DBG(1, "%d\n", ordered[i]);
				}

			}
			cmd[pos] = 0;
		}

	}


	status = esci2_para(s, cmd, pos);
	if (status != SANE_STATUS_GOOD) {
		goto end;
	}

	/* start scanning */
	DBG(1, "%s: scanning...\n", __func__);

	/* switch to data state */
	status = esci2_trdt(s);
	if (status != SANE_STATUS_GOOD) {
		goto end;
	}

	/* first page is page 1 */
	s->pages = 1;
	s->scanning = 1;
	s->dummy = 0;
	s->scanEnd = 0;
end:
	if (status != SANE_STATUS_GOOD) {
		DBG(1, "%s: start failed: %s\n", __func__, sane_strstatus(status));
	}

	return status;
}

static SANE_Status acquire_jpeg_data(epsonds_scanner* s)
{

	SANE_Int read = 0;

	SANE_Int jpegBufSize = s->params.bytes_per_line * s->params.lines;
	if (s->needToConvertBW)
	{
		jpegBufSize = s->params.pixels_per_line * s->params.lines;
	}


	s->frontJpegBuf = malloc(jpegBufSize);
	s->backJpegBuf = malloc(jpegBufSize);
	s->frontJpegBufLen  = 0;
	s->backJpegBufLen = 0;

		// load all images, decode and fill buffer
	SANE_Int status = SANE_STATUS_GOOD;

	int eofFront = 0;
	int eofBack = 0;


	status = eds_ring_init(&s->front, (s->params.bytes_per_line) * s->params.lines);
	if (status != SANE_STATUS_GOOD) {
				return status;
	}

	status = eds_ring_init(&s->back, (s->params.bytes_per_line) * s->params.lines);
	if (status != SANE_STATUS_GOOD) {
			return status;
	}

	while (1)
	{
		status = esci2_img(s, &read);
		DBG(20, "acquire_jpeg_data read: %d, eof: %d, backside: %d, status: %d\n", read, s->eof, s->backside, status);
		if (read)
		{
			if (s->backside)
			{
				SANE_Byte* backBuffer = s->backJpegBuf + s->backJpegBufLen;
				memcpy(backBuffer, s->buf, read);
				s->backJpegBufLen += read;
			}else{
				SANE_Byte* frontBuffer = s->frontJpegBuf +  s->frontJpegBufLen ;
				memcpy(frontBuffer, s->buf, read);
				s->frontJpegBufLen  += read;
			}
		}
		if (status == SANE_STATUS_GOOD)
		{

			DBG(20, "continue acquire image\n");
			continue;
		}
		else if (status == SANE_STATUS_EOF)
		{
			if (s->backside)
			{
				DBG(20, "eofBack\n");
				eofBack = 1;
			}else{
				DBG(20, "eofFront\n");
				eofFront = 1;
			}
		}else if (status == SANE_STATUS_CANCELLED)
		{
				// cancel cleanup
				esci2_can(s);

				free(s->frontJpegBuf);
				free(s->backJpegBuf);
				s->frontJpegBuf = NULL;
				s->backJpegBuf = NULL;
				return status;
		}else{
				// error occurs cleanup
				free(s->frontJpegBuf);
				free(s->backJpegBuf);
				s->frontJpegBuf = NULL;
				s->backJpegBuf = NULL;
				return status;
		}


		if (s->isDuplexScan)
		{
			DBG(20, "eofFront  = %d eofBack  = %d\n", eofFront, eofBack);
				// acquire finish
			if (eofFront && eofBack)
			{
				DBG(20, "eofFront && eofBack end\n");
				break;
			}
		}else{
			if (eofFront)
			{
				DBG(20, "eofFront end\n");
				break;
			}
		 }
	 }

	return SANE_STATUS_GOOD;
}

static SANE_Status
acquire_raw_data(epsonds_scanner* s)
{
	SANE_Int read = 0;

		// load all images, decode and fill buffer
	SANE_Int status = SANE_STATUS_GOOD;

	int eofFront = 0;
	int eofBack = 0;
	int firstWrite = 1;

	while (1)
	{
		DBG(20, "acquire_raw_data loop start\n");
		status = esci2_img(s, &read);
		DBG(20, "acquire_raw_data read: %d, eof: %d, backside: %d, status: %d\n", read, s->eof, s->backside, status);

		if (read)
		{
			if (firstWrite)
			{
				status = eds_ring_init(&s->front, (s->params.bytes_per_line + s->dummy) * s->params.lines);
				if (status != SANE_STATUS_GOOD) {
					return status;
				}

				status = eds_ring_init(&s->back, (s->params.bytes_per_line + s->dummy) * s->params.lines);
				if (status != SANE_STATUS_GOOD) {
					return status;
				}
				firstWrite = 0;
			}

			DBG(20, "eds_ring_write  start\n");
			status = eds_ring_write(s->backside ? &s->back : &s->front, s->buf, read);
			DBG(20, "eds_ring_write  end\n");
		}
		DBG(20, "acquire_raw_data3\n");

		if (status == SANE_STATUS_GOOD)
		{
			DBG(20, "contiune acquire image\n");
			continue;
		}
		else if (status == SANE_STATUS_EOF)
		{
			if (s->backside)
			{
				eofBack = 1;
			}else{
				eofFront = 1;
			}
		}
		else if (status == SANE_STATUS_CANCELLED)
		{
			esci2_can(s);
			return status;
		}else{
				// error occurs cleanup
				return status;
		}

		if (s->isDuplexScan)
		{
			// acquire finish
			if (eofFront && eofBack)
			{
				break;
			}
		}else{
			if (eofFront)
			{
				break;
			}
		}
	}


	int needBytes =  (s->params.bytes_per_line + s->dummy) * s->params.lines;
	{
		int available = eds_ring_avail(&s->front);
		if (available < needBytes)
		{
	 	  int required = needBytes - available;
          	   unsigned char* padding = (unsigned char*)malloc(required);
		   memset(padding, 255, required);
	 	   eds_ring_write(&s->front, padding, required);
		   free(padding);

		}

	}
	{
		int available = eds_ring_avail(&s->back);
		if (available > 0 && available < needBytes)
		{
	 	  int required = needBytes - available;
          	   unsigned char* padding = (unsigned char*)malloc(required);
		   memset(padding, 255, required);
	 	   eds_ring_write(&s->back, padding, required);
		   free(padding);
		}

	}

	if (s->isDuplexScan)
	{
		upside_down_backside_image(s);
	}

	DBG(20, "acquire_raw_data  finish");
	return SANE_STATUS_GOOD;

}

static SANE_Status
acquire_and_decode_jpeg_data(epsonds_scanner* s)
{
		SANE_Int status = acquire_jpeg_data(s);
		if (status == SANE_STATUS_GOOD)
		{
			DBG(20, "** %s:  sane status = %d needToConvertBW = %d \n", __func__, status, s->needToConvertBW);

			// process front page
			if (s->frontJpegBufLen > 0)
			{
				eds_decode_jpeg(s, s->frontJpegBuf, s->frontJpegBufLen,  &s->front,0, s->needToConvertBW);
				free(s->frontJpegBuf);
				s->frontJpegBuf = NULL;
			}
			// process back page
			if (s->backJpegBufLen > 0)
			{
				eds_decode_jpeg(s, s->backJpegBuf, s->backJpegBufLen,  &s->back, 1,  s->needToConvertBW);
				free(s->backJpegBuf);
				s->backJpegBuf = NULL;
			}

			if (s->isDuplexScan)
			{
				upside_down_backside_image(s);
			}
		}else{
			DBG(20, "** %s:  sane finish status = %d\n", __func__, status);
			return status;
		}
		return status;
}

int sumLength = 0;
/* this moves data from our buffers to SANE */
SANE_Status
sane_read(SANE_Handle handle, SANE_Byte *data, SANE_Int max_length, SANE_Int *length)
{
	epsonds_scanner *s = (epsonds_scanner *)handle;
	SANE_Int read = 0;

	if (s->canceling)
	{
		esci2_can(s);
		*length = 0;
		return SANE_STATUS_CANCELLED;
	}

	int available = eds_ring_avail(s->current);
	/* anything in the buffer? pass it to the frontend */
	if (available > 0) {

		DBG(18, "reading from ring buffer, %d left\n", available);

		eds_copy_image_from_ring(s, data, max_length, &read);

				// data is empty fin
		if (read == 0) {
			*length = 0;
			eds_ring_flush(s->current);
			eds_ring_destory(s->current);
			DBG(18, "returns EOF 2\n");
			return SANE_STATUS_EOF;
		}
		*length = read;

		return SANE_STATUS_GOOD;
	}else{
		*length = 0;
		eds_ring_flush(s->current);
		eds_ring_destory(s->current);
		DBG(18, "returns EOF 1\n");
		return SANE_STATUS_EOF;
	}
}

/*
 * void sane_cancel(SANE_Handle handle)
 *
 * Set the cancel flag to true. The next time the backend requests data
 * from the scanner the CAN message will be sent.
 */

void
sane_cancel(SANE_Handle handle)
{
	DBG(1, "** %s\n", __func__);
	((epsonds_scanner *)handle)->canceling = SANE_TRUE;
}

/*
 * SANE_Status sane_set_io_mode()
 *
 * not supported - for asynchronous I/O
 */

SANE_Status
sane_set_io_mode(SANE_Handle __sane_unused__ handle,
	SANE_Bool __sane_unused__ non_blocking)
{
	return SANE_STATUS_UNSUPPORTED;
}

/*
 * SANE_Status sane_get_select_fd()
 *
 * not supported - for asynchronous I/O
 */

SANE_Status
sane_get_select_fd(SANE_Handle __sane_unused__ handle,
	SANE_Int __sane_unused__ *fd)
{
	return SANE_STATUS_UNSUPPORTED;
}
